iText-merged editable PDF loses form data when Acrobat Pro saves as separate PDF - pdf

We're replacing Adobe LiveCycle Server with iText 5.4.1 in an existing webapp to merge XML data with LiveCycle Designer-generated PDF templates, generating editable PDF files from several hundred templates.
This code combines the data with the template, returning a PDF byte array:
// Import data into the PDF form
if (pdfTemplateFileName != null && inputXmlDataFile != null) {
// set up the objects
template = new PdfReader(pdfTemplateFileName);
filledPDF = new ByteArrayOutputStream();
stamper = new PdfStamper(template, filledPDF);
AcroFields form = stamper.getAcroFields();
// fill in the form with the data
XfaForm xfa = form.getXfa();
xfa.fillXfaForm(inputXmlDataFile);
//closing the stamper is necessary to flush to filledPDF
stamper.close();
returnPDF = filledPDF.toByteArray();
}
This code combines the PDF byte arrays into a portfolio:
List<byte[]> assemblingPdfList = assemblingPdfMap.get("newStyleForms");
// create PDF portfolio of editable documents
com.itextpdf.text.Document document = new com.itextpdf.text.Document();
ByteArrayOutputStream mergedPDFOutput = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, mergedPDFOutput);
document.open();
Paragraph coverSheet = new Paragraph("Multiple files are bound together in this PDF Package");
coverSheet.setAlignment(com.itextpdf.text.Element.ALIGN_CENTER);
document.add(coverSheet);
// define the collection
PdfCollection collection = new PdfCollection(PdfCollection.DETAILS);
PdfCollectionSchema schema = new PdfCollectionSchema();
PdfCollectionField filename = new PdfCollectionField("Name", PdfCollectionField.FILENAME);
filename.setOrder(0);
schema.addField("FILENAME", filename);
PdfCollectionField description = new PdfCollectionField("Description", PdfCollectionField.TEXT);
description.setOrder(1);
schema.addField("DESCRIPTION", description);
PdfCollectionField modified = new PdfCollectionField("Modified", PdfCollectionField.MODDATE);
modified.setOrder(2);
schema.addField("MODIFIED", modified);
PdfCollectionField size = new PdfCollectionField("Size", PdfCollectionField.SIZE);
size.setOrder(3);
schema.addField("SIZE", size);
collection.setSchema(schema);
writer.setCollection(collection);
// loop through the PDF documents and add each to the portfolio
PdfFileSpecification fs;
PdfCollectionItem item;
int iNum = 0;
for (byte[] pdf : assemblingPdfList) {
fs = PdfFileSpecification.fileEmbedded(writer, null,
String.format("StylesResult_%s.pdf", iNum++), pdf);
fs.addDescription("Styles Result File", false);
item = new PdfCollectionItem(schema);
item.addItem("DESCRIPTION", "Styles Result File");
item.addItem("MODIFIED", new PdfDate() );
fs.addCollectionItem(item);
writer.addFileAttachment(fs);
}
// close document
document.close();
mergedPDFOutput.flush();
mergedPDFOutput.close();
return mergedPDFOutput.toByteArray();
At first, iText would not populate the form fields. We used LiveCycle Designer to change the data binding of most fields from Normal to Global, which enabled iText to populate most of them correctly. The exception were the repeating (think 'table') rows of data; setting the binding to 'Global' caused the first data value to be repeated down the column for each of the data records. Setting the repeating fields' bindings back to 'Normal' seemed to work.
The iText-merged editable PDF portfolios are launched in Internet Explorer 10. If we click 'Open File' to open an individual PDF in Adobe Acrobat XI Pro, all the data is there. However, if we click 'File' / 'Save As' in Acrobat Pro to save to a new PDF file, then open the new file, some or all of the form data has disappeared (In one case, the 'first generation' save left most of the data intact, but repeating subform data was erased. Saving again, creating a 'second generation' save, erased all data.)
My failed solution attempts include: (a) initializing PdfStamper in 'append' mode; (b) Modifying my PdfStamper with 'stamper.setEncryption(false, "", "", PdfWriter.ALLOW_{everything}...)'.
Adobe LiveCycle Server-generated portfolios do not lose data, no matter how many generations of saves are made.

Related

Dynamic XFA PDF Forms

I have a number of Dynamic XFA PDFs that were created with Livecycle Designer. These PDFs are used as templates for various individuals to complete. When a user requests a template we have to write a submit button with url pointing back to a .net application for processing and update some of the fields with information from the database into the PDF.
Can I use iText(Sharp) with .net to update the dynamic xfa pdf to write into it a submit button and update fields and then use iText(Sharp) to process the returning form.
We are doing this now with Acroforms but need to do the same for Dynamic XFA forms as well. I can’t find any confirmation information that this is possible. If it is possible does anyone have any code that they can share to show me how to do this?
You can also achieve that putting the pdf's content inside an XmlDocument and working as you were working with an XML.
This is the code I use to replace some placeholders written in textboxes.
PdfReader pdfReader = new PdfReader(path_pdf);
using (PdfStamper pdfStamp = new PdfStamper(pdfReader, new FileStream(temp_path, FileMode.Create), '\0', true))
{
pdfStamp.ViewerPreferences = PdfWriter.AllowModifyContents;
XmlDocument xmlDocument = pdfReader.AcroFields.Xfa.DomDocument;
string pdfContent = xmlDocument.InnerXml;
string newpdfContent = pdfContent
.Replace("$CONTENT_TO_REPLACE_1$", "some_content")
.Replace("$CONTENT_TO_REPLACE_2$", "some_other_content")
xmlDocument.InnerXml = newpdfContent;
Stream stream = GenerateStreamFromString(newpdfContent);
pdfStamp.AcroFields.Xfa.FillXfaForm(stream);
pdfStamp.AcroFields.Xfa.DomDocument = xmlDocument;
pdfStamp.Close();
}

Adding an imported PDF to a table cell in iTextSharp

I am creating a new PDF that will contain a compilation of other documents.
These other documents can be word/excel/images/PDF's.
I am hoping to add all of this content to cells in a table, which is added to the document - this gives me the goodness of automatically adding pages, positioning elements in a cell rather than a page and allowing me an easier life at keeping content in the same order as i supply (such as img, doc, pdf, img, pdf etc)
Adding images to the table is simple enough.
I am converting the word/excel docs to PDF image streams. I'm also reading in the existing PDF's as a stream.
Adding these to a new PDF is simple enough - by way of adding a template to the PdfContent byte.
What I am trying to do though is add these PDF's to cells in a table, which are then added to the doc.
Is this possible?
Please download chapter 6 of my book. It contains two variations on what you are trying to do:
ImportingPages1, with as result time_table_imported1.pdf
ImportingPages2, with as result time_table_imported2.pdf
This is a code snippet:
// step 1
Document document = new Document();
// step 2
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(RESULT));
// step 3
document.open();
// step 4
PdfReader reader = new PdfReader(MovieTemplates.RESULT);
int n = reader.getNumberOfPages();
PdfImportedPage page;
PdfPTable table = new PdfPTable(2);
for (int i = 1; i <= n; i++) {
page = writer.getImportedPage(reader, i);
table.getDefaultCell().setRotation(-page.getRotation());
table.addCell(Image.getInstance(page));
}
document.add(table);
// step 5
document.close();
reader.close();
The pages are imported as PdfImportedPage objects, and then wrapped inside an Image so that we can add them to a PdfPTable.

itextsharp stamper vs smartcopy, show pdf in browser without toolbar or navpanes

My application is grabbing pdf bytes from our db and sending the pdf to an iframe, using the itextsharp library. When the pdf is displayed in the iframe, the toolbar and navigation pane show, but we'd like to hide those. When I load a pdf document by simply typing in the pdf's url with #toolbar=0&navpanes=0, I see the result I'm looking for.
The application logic is using PdfStamper to add some buttons and other data to the pdf. When I write the pdf to the Response.Outputstream, the pdf shows up with the added buttons, and all is good except that I can't get rid of the toolbar and navpanes. I've tried adding "toolbar=0&navpanes=0" to the url in the response header, but to no avail.
I've written a test application which shows that using PdfSmartCopy instead of the stamper works perfectly - the pdf is shown in the browser which hides the toolbar and navpane by default.
The problem is that I still need to add some buttons to the pdf via the stamper. I've written a test app which adds the buttons via the stamper, then the smart copy grabs each page from the stamper and writes all this out to the Response.Output. The pdf shows in the browser with no toolbar or navpanes, but the buttons are not there.
Here is the code which uses both the stamper and the smart copy - your help is greatly appreciated:
private void SendStamperToCopy()
{
try
{
String filePath = #"C:\debug\PerfIndicWithDefaults.pdf";
byte[] pdfBytes = ReadFile(filePath);
Document document = new Document();
PdfSmartCopy copy = new PdfSmartCopy(document, Response.OutputStream);
document.Open();
MemoryStream memStream = new MemoryStream();
PdfReader reader = new PdfReader(pdfBytes);
PdfStamper pdfStamper = new PdfStamper(reader, memStream);
// add a button with the stamper
iTextSharp.text.Rectangle rectCancel = new iTextSharp.text.Rectangle(50, 50, 20, 20);
PushbuttonField btnCancel = new PushbuttonField(pdfStamper.Writer, rectCancel, "Cancel");
btnCancel.Text = "Cancel";
iTextSharp.text.pdf.PdfAnnotation fieldCancel = btnCancel.Field;
pdfStamper.AddAnnotation(fieldCancel, 1);
int numOfPgs = reader.NumberOfPages;
for (int n = 1; n <= numOfPgs; n++)
{
copy.AddPage(pdfStamper.GetImportedPage(reader, n));
}
String headerStr = "inline; filename=PerfIndicWithDefaults.pdf";
Response.AppendHeader("content-disposition", headerStr);
Response.ContentType = "application/pdf";
Response.OutputStream.Flush();
document.Close();
Response.OutputStream.Close();
}
catch (Exception ex)
{
Console.Write(ex);
Response.OutputStream.Flush();
Response.OutputStream.Close();
}
}
If I understand your question correctly, you want to use PdfStamper to add a button and you want to change the viewer preferences. This can be done like this:
PdfReader reader = new PdfReader(source);
System.IO.MemoryStream m = new System.IO.MemoryStream();
PdfStamper stamper = new PdfStamper(reader, m);
PdfStamper.ViewerPreferences = PdfWriter.HideToolbar | PdfWriter.PageModeUseNone;
stamper.Close();
reader.Close();
The HideToolbar will hide the toolbar, whereas PageModeUseNone means that you don't show any panels (such as the bookmarks panel, etc...).
It is not clear why you would need PdfSmartCopy in this context. Maybe I'm missing something. Also: there are some strange errors in your code: you never close the stamper instance, yet you import a page from the stamper into the copy instance. I've never seen any one try that. It's certainly not what I had in mind when I wrote iText. Your code is very confusing to me.

Losing javascript which is added into pdf using itext

I am trying to add javascript into a pdf using itext and later merge it with another pdf.
But the final merged pdf does not contain the javascript. The javascript is working fine if the pdf is not merged with another pdf.
Merging code :
FileOutputStream sectionR = new FileOutputStream(RESULT);
PdfCopyFields copier = new PdfCopyFields(sectionR);
for (String curInPath : listFile) {
PdfReader reader = new PdfReader(curInPath);
copier.addDocument(reader);
}
copier.close();
I tried to add JS to the resulting merged pdf, but it is not taking it. I guess its not editable.
Below is the code adding JS to pdf which is not merged yet.
FileOutputStream section1Pdf = new FileOutputStream("newPDFSection");
PdfReader readerSection1 = new PdfReader("Existing PDF - Section 1");
PdfStamper stamperSection1 = new PdfStamper(readerSection1,section1Pdf);
stamperSection1.addJavaScript(
"var nameField = this.getField('txtOwnerCity');" + "nameField.setAction('Keystroke'," +"'forceUpperCase()');" +
"" +"function forceUpperCase(){" +
"if(!event.willCommit)event.change = " +
"event.change.toUpperCase();" +
"}");
When I tried adding JS to the resulting merged pdf, it does not allow me saying it is not editable anymore.
This is how I am trying to add
FileOutputStream sectionR = new FileOutputStream(RESULT);
PdfCopyFields copier = new PdfCopyFields(sectionR);
for (String curInPath : listFile) {
PdfReader reader = new PdfReader(curInPath);
copier.addDocument(reader);
}
copier.close();
PdfReader readersectionResult = new PdfReader("result.pdf");
PdfStamper stamper = new PdfStamper(readersectionResult, new FileOutputStream("newResult.pdf"));
stamper.addJavaScript(some JS);
The error I am getting is ' WARNING: Cannot set header. Response already committed.'
I am not sure if I am doing it right above, All I am trying to do is get pdfstamper of resulting pdf to add new JS to it.
When I am trying to edit form filed values, it says not editable anymore.
AcroFields acro= stamper .getAcroFields();
acro.setField("txtOfficerName"+officerChar,officerSO.getFullName());

How can I convert a web form to pdf using itextsharp?

I am trying to convert a web form to a pdf after a user fills in the fields in the web form. Is this possible? All i can do right now is loop through the form collection and print out the field name and the field value to the pdf. Is there a way to do this and keep the pdf looking like the web form?
I'm using mvc 3 for the web page.
Thanks!
Now I am using the following which converts everything in the form but the form fields.
Document doc = new Document();
String path = "C:\\projects\\pdfs\\";
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(path + "Doc1.pdf", FileMode.Create));
StringReader sr = new StringReader(htmlString);
HTMLWorker worker = new HTMLWorker(doc);
doc.Open();
worker.Parse(sr);
doc.Close();
How do I get the form fields to display in the pdf?