I need to render each cell values in a new page.
I am using the following code :
List<string> values = getValues(); // getValues() method returns a list of strings
Document doc = new Document();
....
PdfPTable table = new PdfPTable(1);
foreach(var s in values)
{
table.AddCell(s);
doc.NewPage();
}
...
But I am getting the output in a single page.
Add a one-cell table on each page:
List<string> values = getValues(); // getValues() method returns a list of strings
Document doc = new Document();
....
foreach(var s in values)
{
PdfPTable table = new PdfPTable(1);
table.AddCell(s);
doc.add(table);
doc.NewPage();
}
...
Related
I have this code to create TextFields
public void MssCreateTextField(byte[] ssPdf, RCRectangleRecord ssRectangle, string ssName, int ssFontSize, string ssValue, int ssPage, out byte[] ssPdfOut, bool ssIsMultiline) {
PdfReader reader = new PdfReader(ssPdf);
ssPdfOut = null;
var output = new MemoryStream();
var stamper = new PdfStamper(reader, output);
/*TextField tField = new TextField(stamper.Writer, new iTextSharp.text.Rectangle((float)ssRectangle.ssSTRectangle.ssllx, (float)ssRectangle.ssSTRectangle.sslly, (float)ssRectangle.ssSTRectangle.ssurx, (float)ssRectangle.ssSTRectangle.ssury), ssName);
if (ssValue!="")
tField.Text = ssValue;
if (ssIsMultiline)
tField.Options = TextField.MULTILINE;
tField.FontSize = ssFontSize;*/
PdfFormField tField = PdfFormField.CreateTextField(stamper.Writer, ssIsMultiline, false, 50);
tField.FieldName = ssName;
tField.SetWidget(new iTextSharp.text.Rectangle((float)ssRectangle.ssSTRectangle.ssllx, (float)ssRectangle.ssSTRectangle.sslly, (float)ssRectangle.ssSTRectangle.ssurx, (float)ssRectangle.ssSTRectangle.ssury), PdfAnnotation.HIGHLIGHT_TOGGLE);
stamper.FormFlattening = false;
stamper.AddAnnotation(tField, ssPage);
stamper.Close();
reader.Close();
ssPdfOut = output.ToArray();
}
As you can see i have some code commented as an alternative but the two different ways are producing the same result.
What i am trying to achieve is create two textfields with the same name to when editing one it edits the others two. This two codes do that (in the browsers and pdfescape site) excepting in the adobe acrobat reader. In the acrobat reader i get just the first field visible and the others hidden i dont know why...
If you want to add two text field visualizations which represent the same content, you have to add them as two widgets of the same field and not two distinct fields, e.g. like this:
public void CreateDoubleTextField(byte[] ssPdf, Rectangle ssRectangle1, Rectangle ssRectangle2, string ssName, int ssFontSize, string ssValue, int ssPage, out byte[] ssPdfOut, bool ssIsMultiline)
{
PdfReader reader = new PdfReader(ssPdf);
ssPdfOut = null;
var output = new MemoryStream();
var stamper = new PdfStamper(reader, output);
PdfFormField tField = PdfFormField.CreateTextField(stamper.Writer, ssIsMultiline, false, 50);
tField.FieldName = ssName;
PdfFormField widget1 = PdfFormField.CreateEmpty(stamper.Writer);
widget1.SetWidget(ssRectangle1, PdfAnnotation.HIGHLIGHT_TOGGLE);
PdfFormField widget2 = PdfFormField.CreateEmpty(stamper.Writer);
widget2.SetWidget(ssRectangle2, PdfAnnotation.HIGHLIGHT_TOGGLE);
tField.AddKid(widget1);
tField.AddKid(widget2);
stamper.FormFlattening = false;
stamper.AddAnnotation(tField, ssPage);
stamper.Close();
reader.Close();
ssPdfOut = output.ToArray();
}
(As I don't have that RCRectangleRecord, I use the iTextSharp Rectangle class as argument.)
This gives you two field visualizations in Adobe Acrobat Reader; after editing one of them and switching focus (e.g. clicking somewhere outside that visualization), the other visualization duplicates the content.
Now i have this and i can create two fields when the list has more than one Rectangle but for some reason i dont know how the two fields appears without the name!!
PdfReader reader = new PdfReader(ssPdf);
ssPdfOut = null;
var output = new MemoryStream();
var stamper = new PdfStamper(reader, output);
TextField tField;
if (ssRectangle.Count==1){
tField= new TextField(stamper.Writer, new iTextSharp.text.Rectangle((float)ssRectangle[0].ssSTRectangle.ssllx, (float)ssRectangle[0].ssSTRectangle.sslly, (float)ssRectangle[0].ssSTRectangle.ssurx, (float)ssRectangle[0].ssSTRectangle.ssury), ssName);
if (ssValue!="")
tField.Text = ssValue;
if (ssIsMultiline)
tField.Options = TextField.MULTILINE;
tField.FontSize = ssFontSize;
tField.FieldName = ssName;
stamper.AddAnnotation(tField.GetTextField(), ssPage);
}
else
{
PdfFormField PtField = PdfFormField.CreateTextField(stamper.Writer, ssIsMultiline, false, 250);
PtField.Name=ssName;
foreach (RCRectangleRecord item in ssRectangle)
{
/*
tField=new TextField(stamper.Writer, new iTextSharp.text.Rectangle((float)ssRectangle[0].ssSTRectangle.ssllx, (float)ssRectangle[0].ssSTRectangle.sslly, (float)ssRectangle[0].ssSTRectangle.ssurx, (float)ssRectangle[0].ssSTRectangle.ssury), ssName);
tField.FieldName = ssName;
PtField.AddKid(tField.GetTextField());*/
PdfFormField widget = PdfFormField.CreateEmpty(stamper.Writer);
widget.SetWidget(new Rectangle((float)item.ssSTRectangle.ssllx, (float)item.ssSTRectangle.sslly, (float)item.ssSTRectangle.ssurx, (float)item.ssSTRectangle.ssury), PdfAnnotation.HIGHLIGHT_TOGGLE);
widget.Name = ssName;
PtField.AddKid(widget);
}
stamper.AddAnnotation(PtField, ssPage);
}
stamper.FormFlattening = false;
stamper.Close();
reader.Close();
ssPdfOut = output.ToArray();
The code below is correctly assigning the value "foo" to the named field, but the field is not being "flattened". I must be neglecting a step, but I don't know what it is. Please advise. Thanks.
public byte[] FlattenSpecifiedFormFields(byte[] b, List<string> fieldNames2Flatten)
{
PdfReader reader = new PdfReader(b);
using (var ms = new MemoryStream())
{
var stamper = new iTextSharp.text.pdf.PdfStamper(reader, ms);
foreach (string name in fieldNames2Flatten)
{
stamper.AcroFields.SetField(name, "foo");
stamper.PartialFormFlattening(name);
}
stamper.Close();
return ms.ToArray();
};
}
Even when partially flattening a form, the PdfStamper FormFlattening property must be set to true. I.e.:
var stamper = new PdfStamper(reader, ms);
stamper.FormFlattening = true;
foreach (string name in fieldNames2Flatten)
{
stamper.AcroFields.SetField(name, "foo");
stamper.PartialFormFlattening(name);
}
the following code does produce the table and the nested table.
However, the nested table is always aligned in the middle.
I have no clue how to achieve horizontal alignment properly.
The following method is simply looping through a list.
when it's a simple question, I will add an TextField.
if it's a question containing multiple answers, i will inject a nested table with the checkboxes and the values.
private PdfPTable CreateQuestionTable(RLQuestionRecordList questions)
{
PdfPCell cell;
PdfPTable table = new PdfPTable(2);
//table.SetWidths(new int[]{ 50, 50 });
table.WidthPercentage = 100;
table.SpacingBefore = 20;
table.SpacingAfter = 20;
table.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT;
foreach (RCQuestionRecord q in questions)
{
//add question to the table
cell = new PdfPCell(new Phrase(q.ssSTQuestion.ssName, _Normal));
cell.Border = Rectangle.NO_BORDER;
cell.Padding = 5.0f;
table.AddCell(cell);
//add answer to the table.
//add generate time we don;t know where the table will be,
//hence textfields will be generated after the pdf has been generated..
if (q.ssSTQuestion.ssListOfAnswers.Length > 0)
{
// we have radiobuttons, so we add a table inside the cell
cell = new PdfPCell();
cell.Border = Rectangle.NO_BORDER;
cell.Padding = 5.0f;
//we cannot align the table to the left in the cell for some weird reason...
cell.HorizontalAlignment = Element.ALIGN_LEFT;
cell.AddElement(CreateCheckboxTable(q));
table.AddCell(cell);
}
else
{
// we have simple textfield, so add that to the cell
cell = new PdfPCell();
cell.Border = Rectangle.NO_BORDER;
cell.Padding = 5.0f;
cell.HorizontalAlignment = Element.ALIGN_LEFT;
//simple textfield
cell.CellEvent = new OOMTextField(string.Format("question_{0}", q.ssSTQuestion.ssQuestionId), q.ssSTQuestion.ssLength, q.ssSTQuestion.ssValue, bf);
table.AddCell(cell);
}
}
return table;
}
This is the nested table I want to insert into the cell above.
/// <summary>
///
/// </summary>
/// <param name="question"></param>
/// <returns></returns>
private PdfPTable CreateCheckboxTable(RCQuestionRecord question)
{
PdfPCell cell;
int numCells = question.ssSTQuestion.ssListOfAnswers.Length;
PdfPTable table = new PdfPTable(numCells);
float[] widths = new float[numCells];
int currentColumn = 0;
//table.SetWidths(new int[]{ 50, 50 });
foreach (RCAnswerRecord a in question.ssSTQuestion.ssListOfAnswers) {
//checkbox
cell = new PdfPCell(new Phrase(a.ssSTAnswer.ssLabel, _Normal));
cell.Border = Rectangle.NO_BORDER;
cell.Padding = 0.0f;
cell.PaddingLeft = 20.0f;
cell.HorizontalAlignment = Element.ALIGN_LEFT;
cell.VerticalAlignment = Element.ALIGN_CENTER;
cell.CellEvent = new OOMCheckBox(string.Format("question_{0}", question.ssSTQuestion.ssQuestionId), a.ssSTAnswer.ssIsSelected, a.ssSTAnswer.ssLabel, bf);
//checkbox
table.AddCell(cell);
widths[currentColumn++] = 20.0f + bf.GetWidthPoint(a.ssSTAnswer.ssLabel, 11);
}
table.SetTotalWidth(widths);
table.LockedWidth = true;
table.SpacingBefore = 0;
return table;
}
What am I missing to align the nested tables totally to the left inside the cell?
Please take a look at the PDF document named nested_tables_aligned.pdf:
The outer table in this example has three columns and one row. Each cell in this outer table contains an inner table. The first inner table is left aligned, the second one is center aligned, the third one is right aligned.
This PDF was created with the Java example named NestedTablesAligned:
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document(PageSize.A4.rotate());
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
float[] columnWidths = {200f, 200f, 200f};
PdfPTable table = new PdfPTable(columnWidths);
table.setTotalWidth(600f);
table.setLockedWidth(true);
buildNestedTables(table);
document.add(table);
document.close();
}
private void buildNestedTables(PdfPTable outerTable) {
PdfPTable innerTable1 = new PdfPTable(1);
innerTable1.setTotalWidth(100f);
innerTable1.setLockedWidth(true);
innerTable1.setHorizontalAlignment(Element.ALIGN_LEFT);
innerTable1.addCell("Cell 1");
innerTable1.addCell("Cell 2");
outerTable.addCell(innerTable1);
PdfPTable innerTable2 = new PdfPTable(2);
innerTable2.setTotalWidth(100f);
innerTable2.setLockedWidth(true);
innerTable2.setHorizontalAlignment(Element.ALIGN_CENTER);
innerTable2.addCell("Cell 3");
innerTable2.addCell("Cell 4");
outerTable.addCell(innerTable2);
PdfPTable innerTable3 = new PdfPTable(2);
innerTable3.setTotalWidth(100f);
innerTable3.setLockedWidth(true);
innerTable3.setHorizontalAlignment(Element.ALIGN_RIGHT);
innerTable3.addCell("Cell 5");
innerTable3.addCell("Cell 6");
outerTable.addCell(innerTable3);
}
As you can see, I define the alignment of the table at the level of the table, not at the level of the cell. The sample principle applies to iTextSharp. In you C# example, you define the aligned for the PdfPCell instead of for the PdfPTable. Change this and your problem will be solved.
Have a little method which goes to the database and retrieves a pdf document from a varbinary column and then adds data to it. I would like to add code so that if this document (company stationery ) is not found then a new blank document is created and returned. The method could either return a Byte[] or a Stream.
Problem is that the variable "bytes" in the else clause is null.
Any ideas what's wrong?
private Byte[] GetBasePDF(Int32 AttachmentID)
{
Byte[] bytes = null;
DataTable dt = ServiceFactory
.GetService().Attachments_Get(AttachmentID, null, null);
if (dt != null && dt.Rows.Count > 0)
{
bytes = (Byte[])dt.Rows[0]["Data"];
}
else
{
// Create a new blank PDF document and return it as Byte[]
ITST.Document doc =
new ITST.Document(ITST.PageSize.A4, 50f, 50f, 25f, 25f);
MemoryStream ms = new MemoryStream();
PdfCopy copy = new PdfCopy(doc, ms);
ms.Position = 0;
bytes = ms.ToArray();
}
return bytes;
}
You are trying to use PdfCopy but that's intended for existing documents, not new ones. You just need to create a "blank" document using PdfWriter and Document. iText won't let you create a 100% empty document but the code below essentially does that by just adding a space.
private static Byte[] CreateEmptyDocument() {
using (var ms = new System.IO.MemoryStream()) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
doc.Add(new Paragraph(" "));
doc.Close();
}
}
return ms.ToArray();
}
}
I think you may need to use
bytes = ms.GetBuffer();
not
bytes = ms.ToArray();
I have a document that I am iterating thru getting the paragraphs. For each of these paragraphs I need to create a new document and save it. I can't figure out how to add a Paragraph from the source document to the new one.
foreach (var p in paragraphsFromSourceDocument)
{
using (var memoryStream = new MemoryStream())
{
var doc = WordprocessingDocument.Create(memoryStream, WordprocessingDocumentType.Document);
doc.AddMainDocumentPart();
// Create the Document DOM.
doc.MainDocumentPart.Document = new Document();
doc.MainDocumentPart.Document.Body = new Body();
//Add the paragraph 'p' to the Body here:
// HOW ?????????
doc.MainDocumentPart.Document.Save();
}
}
// Open the file read-only since we don't need to change it.
using (var wordprocessingDocument = WordprocessingDocument.Open(documentFileName, true))
{
paragraphs = wordprocessingDocument.MainDocumentPart.Document.Body
.OfType<Paragraph>().ToList();
styles = wordprocessingDocument.MainDocumentPart.StyleDefinitionsPart;
foreach (var p in paragraphs)
{
using (var memoryStream = new MemoryStream())
{
var doc = WordprocessingDocument.Create(memoryStream, WordprocessingDocumentType.Document);
doc.AddMainDocumentPart().AddPart(styles);
doc.MainDocumentPart.Document = new Document();
doc.MainDocumentPart.Document.Body = new Body();
doc.MainDocumentPart.Document.Body.Append(p.CloneNode(true));
doc.MainDocumentPart.Document.Save();
Console.WriteLine(GetHTMLOfDoc(doc));
}
}
}