How to update formatting by an uncalculated field and update Calculated fields in the form of a Fillable PDF

I have a PDF file that I am trying to fill with the contents of "MyDocument". All fields are filled out normally, but the problem is that the "Calculated" fields in my PDF file are not updated, nor are they formatted in other fields. How to force processed fields to update and format using ITextSharp? (I don't care if I get a response in C # or VB.NET)

VB.NET:

Public Shared Sub Serialize(ByVal stmt As MyDocument, ByVal file As FileInfo) Dim reader As New PdfReader(TemplateFilePath.FullName) Dim pdfStamper As New PdfStamper(reader, New FileStream(file.FullName, FileMode.Open)) Try With itsDaDetailFields .MoveFirst() While Not .EOF Dim pdfFieldName As String = NsT(Of String)(!PDFFieldName, Nothing) If Not String.IsNullOrEmpty(pdfFieldName) Then Dim value As String = NsT(Of String)(stmt.GetValueFromPDFField(pdfFieldName), Nothing) If Not String.IsNullOrEmpty(value) Then pdfStamper.AcroFields.SetField(pdfFieldName, value) End If End If .MoveNext() End While End With Finally pdfStamper.FormFlattening = False reader.Close() pdfStamper.Close() End Try End Sub 

FROM#:

 public static void Serialize(MyDocument stmt, FileInfo file) { PdfReader reader = new PdfReader(TemplateFilePath.FullName); PdfStamper pdfStamper = new PdfStamper(reader, new FileStream(file.FullName, FileMode.Open)); try { var _with1 = itsDaDetailFields; _with1.MoveFirst(); while (!_with1.EOF) { string pdfFieldName = NsT<string>(_with1["PDFFieldName"], null); if (!string.IsNullOrEmpty(pdfFieldName)) { string value = NsT<string>(stmt.GetValueFromPDFField(pdfFieldName), null); if (!string.IsNullOrEmpty(value)) { pdfStamper.AcroFields.SetField(pdfFieldName, value); } } _with1.MoveNext(); } } finally { pdfStamper.FormFlattening = false; reader.Close(); pdfStamper.Close(); } } 
+1
c # itextsharp
source share
2 answers

So, I figured out how to do this in .NET based on the following message using iText (java version of ITextSharp - the procedure is slightly different for .net). Feel free to read the following thread for a full explanation and discussion of the same issue in iText:

http://itext-general.2136553.n4.nabble.com/Setting-acroform-value-via-iText-messes-with-acrofield-formating-td2167101.html

There are two ways to do this:

(1) Indicate the displayed value, for example:

 pdfStamper.AcroFields.SetField(pdfFieldName, value, <formatted value>) 

how in:

 pdfStamper.AcroFields.SetField(pdfFieldName, 1000, "1,000") 

This was not optimal for me, because I could not calculate the program from my PDF file, the text fields of which formatted their contents in what format. Some had slightly different formats (some had 2 decimal places, some had 0, some had a lot), so if you can keep track of how the text field formats its data or they all do the same, then this might work . This also did not fix the problem with the computed fields, but simply complicated the formatting problem.

(2) Provide javascript for the "DIRTY" value so that it is formatted and evaluated:

My code turned into something like the following, since I only needed to format the numeric values, but this could be extended to handle other types (see discussion below).

 Dim reader As New PdfReader(TemplateFilePath.FullName) Dim pdfStamper As New PdfStamper(reader, New FileStream(file.FullName, FileMode.Open)) With pdfStamper.AcroFields If IsNumeric(value) Then Dim js As String = String.Format("var f = this.getField('{0}'); f.value = 1 * f.value;", pdfFieldName) pdfStamper.JavaScript = js End If .SetField(pdfFieldName, value) End With reader.Close() pdfStamper.Close() 

So, the trick is that you need to use JavaScript to get the value dirty, then Reader will apply formatting. You can generalize this more and process more types of values ​​based on the complete solution presented below (sorry that it is in java, but can be adapted to .net):

 import java.io.IOException; import java.util.ArrayList; import com.lowagie.text.pdf.PRStream; import com.lowagie.text.pdf.PdfDictionary; import com.lowagie.text.pdf.PdfName; import com.lowagie.text.pdf.PdfObject; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfString; import com.lowagie.text.pdf.AcroFields.Item; public class AcroFieldJSScanner { protected ArrayList<String> functions = null; public void getFieldFunctions(Item item) throws IOException{ PdfDictionary dict; for (int i = 0; i < item.size(); i++) { dict = item.getMerged(i); scanPdfDictionary(dict); // dict = item.getWidget(i); // // scanPdfDictionary(dict); } } protected void scanPdfDictionary(PdfDictionary dict) throws IOException{ PdfObject objJS = null; String func = null; objJS = dict.get(PdfName.JS); if (dict.get(PdfName.S) != null && objJS != null && objJS.isString()){ PdfString strJS = (PdfString)objJS; if (functions == null){ functions = new ArrayList<String>(); } func = strJS.toString(); functions.add(func); }else if (dict.get(PdfName.S) != null && objJS != null){ for(Object obj : dict.getKeys()){ PdfName pdfName = (PdfName)obj; PdfObject pdfObj = dict.get(pdfName); if (pdfObj.isIndirect()){ PdfObject pdfIndirectObject = PdfReader.getPdfObject(pdfObj); func = new String(PdfReader.getStreamBytes((PRStream)pdfIndirectObject)); if (functions == null){ functions = new ArrayList<String>(); } functions.add(func); }else{ scanPdfObject(pdfObj); } } }else{ for(Object obj : dict.getKeys()){ PdfName pdfName = (PdfName)obj; PdfObject pdfObj = dict.get(pdfName); scanPdfObject(pdfObj); } } } protected void scanPdfObject(PdfObject parentPdfObject) throws IOException{ if (parentPdfObject.isDictionary()){ scanPdfDictionary((PdfDictionary)parentPdfObject); }else if (parentPdfObject.isIndirect()){ PdfObject pdfObject = PdfReader.getPdfObject(parentPdfObject); scanPdfObject(pdfObject); } } public ArrayList<String> getFunctions() { return functions; } public String toString(){ StringBuilder sb = null; if (getFunctions() != null){ sb = new StringBuilder(); for (int i =0; i< getFunctions().size();i++) { sb.append(getFunctions().get(i)).append("\n"); } }else{ return "No functions found"; } return sb.toString(); } } 

And then, if you know the javascript scripts that Adobe will call (using the code above), you know what type of data is such that you can "DIRTY" the data. The following are some adobe and javascript data types that are behind these data types:

 public String getFieldFormat(Item item){ PdfDictionary aa = (PdfDictionary) item.getMerged(0).get(PdfName.AA); if (null != aa) { PdfDictionary f = (PdfDictionary)PdfReader.getPdfObject(aa.get(PdfName.F)); if (null != f) { PdfString js = (PdfString)PdfReader.getPdfObject(f.get(PdfName.JS)); if (null != js) { String sScriptName = js.toString(); if (sScriptName.contains("AFNumber_Format")) System.out.println("Format : Number"); else if (sScriptName.contains("AFDate_Format")) System.out.println("Format : Date"); else if (sScriptName.contains("AFTime_Format")) System.out.println("Format : Time"); else if (sScriptName.contains("AFSpecial_Format")) System.out.println("Format : Special"); else if (sScriptName.contains("AFPercent_Format")) System.out.println("Format : Percent"); else System.out.println("Format : Custom");; System.out.println("JS: "); System.out.println(js); } } } } 
+3
source share

In my case, I found out that:

  • Using FormFlattening does not allow javascript to update the field
  • Setting a field using SetField does not result in formatting.

So I had to modify javascript to actually write the full value, and not just pollute it. For example:

 JS &= String.Format("var f = this.getField('{0}'); f.value = '{1}';", FieldName.Key, NewFieldValue) 

I add javascript code for each field to the JS string and then I call pdfStamper.Javascript = JS at the end.

+1
source share

All Articles