Underline form field value using itextsharp

2019-09-01 15:10发布

问题:

I have an application that uses itextsharp to fill PDF form fields.

I got new requirement from the customer to allow underlining the fields values.

I have read many posts including answers to questions in this site but I could't figure out a way to do it.

Current my code does the following:

  1. Creates a PDFStamper instance
  2. Get the form fields using stamper.AcroFields property
  3. Set the field value using the AcroFields.SetFieldRichValue() method.

But when I am opening the PDF the field is empty.

I verified that the field is set as rich text in the PDF itself.

Any idea what I am doing wrong ?

Here is a snnipest of my code:

                FileStream stream = File.Open(targetFile, FileMode.Create);                                     
                var pdfStamper = new PdfStamper(new PdfReader(sourceFile), stream);                     

                // Iterate the fields in the PDF
                foreach (var fieldName in pdfStamper.AcroFields.Fields.Keys)
                {                       
                    // Get the field value of the current field
                    var fieldValue = "<?xml version=\"1.0\"?><body xmlns=\"http://www.w3.org/1999/xtml\" xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\" xfa:contentType=\"text/html\" xfa:APIVersion=\"Acrobat:8.0.0\" xfa:spec=\"2.4\"><p style=\"text-align:left\"><b><i>Here is some bold italic text</i></b></p><p style= \"font-size:16pt\">This text uses default text state parameters but changes the font size to 16.</p></body>"

                    // Set the field value
                    if (String.IsNullOrEmpty(fieldValue) == false)
                    {
                        pdfStamper.AcroFields.SetFieldRichValue(key, fieldValue);
                    }
                }

Edit:

I have revised my code based on Mark Storer's post to a question (http://stackoverflow.com/questions/1454701/adding-rich-text-to-an-acrofield-in-itextsharp). The new code is:

        // Create reader to read the source file
        var reader = new PdfReader(sourceFile);

        // Create a stream for the generated file
        var stream = File.Open(targetFile, FileMode.Create); 

        // Create stamper to generate the new file
        var pdfStamper = new PdfStamper(reader, stream);

        // Field name and value
        var fieldName = "myfield";
        var fieldValue = "<?xml version=\"1.0\"?><body xfa:APIVersion=\"Acroform:2.7.0.0\" xfa:spec=\"2.1\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\"><p dir=\"ltr\" style=\"margin-top:0pt;margin-bottom:0pt;font-family:Helvetica;font-size:12pt\"><b>write line1 bold</b></p</body>";

        // Output stream for the temporary file that should contain the apearance of the field
        var msOutput = new FileStream(@"d:\temp.pdf", FileMode.Create);

        // string reader to read the field value
        var textReader = new StringReader(fieldValue);

        // Create new document
        var document = new Document(pdfStamper.AcroFields.GetFieldPositions(fieldName)[0].position);

         // writer for the new doucment
        var writer = PdfWriter.GetInstance(document, msOutput);

        // Open the document                
        document.Open();

        // Get elements to append to the doucment
        var list = HTMLWorker.ParseToList(textReader, null);

        // Append elements to the doucment
        foreach (var element in list)
        {
            document.Add(element);
        }                                           

        // close the documnet
        document.Close();                            

        // Append push button that contains the generated content as its apearance
        // this approach is based on the suggestion from Mark storer that can be found in:
        // http://stackoverflow.com/questions/1454701/adding-rich-text-to-an-acrofield-in-itextsharp
        var button = new PushbuttonField(pdfStamper.Writer, pdfStamper.AcroFields.GetFieldPositions(fieldName)[0].position, fieldName + "_")
                             {
                                 Layout = PushbuttonField.LAYOUT_ICON_ONLY,
                                 BackgroundColor = null,
                                 Template = pdfStamper.Writer.GetImportedPage(new PdfReader(targetFile, 1)
                             };
            pdfStamper.AddAnnotation(button.Field, 1);                

        pdfStamper.FormFlattening = true;
        pdfStamper.Close();
        pdfStamper.Dispose();

But the problem now is that the temporary document contains no content....

Any ideas ?

回答1:

There's a lot of code above, almost 400 lines. In the future, try to distill everything down to a very simple and reproducible test case.

When using SetFieldRichValue you also need to set the PdfStamper's AcroFields.GenerateAppearances property to false:

stamper.AcroFields.GenerateAppearances = false;

You can read more about this here along with some caveats and other workarounds.



回答2:

I managed to resolve it with little trick - I used Anchor (hyperling) element inside ColumnText element and position it above the form field. The anchor is displayed with underline by default. In order to avoid the hand marker when the user hover the mouse on the anchor, I set the "Reference" property of the anchor to null.

Here is the code I used:

 // Create reader
 var reader = new PdfReader(sourceFilePathAndName);

 // Create stream for the target file
 var stream = File.Open(targetFilePathAndName, FileMode.Create); 

 // Create the stamper
 var pdfStamper = new PdfStamper(reader, stream);

 const string fieldName = "MyField";     

 // Get the position of the field
 var targetPosition = pdfStamper.AcroFields.GetFieldPositions(fieldName)[0].position;

 // Set the font
 var fontNormal = FontFactory.GetFont("Arial", 16, Font.UNDERLINE, BaseColor.BLACK);

 // Create the anchor
 var url = new Anchor("some default text", fontNormal) { Reference = null };

 // Create the element that will contain the anchor and allow to position it anywhere on the document
 var data = new ColumnText(pdfStamper.GetOverContent(1));

 // Add the anchor to its container
 data.SetSimpleColumn(url, targetPosition.Left, targetPosition.Bottom, targetPosition.Right, targetPosition.Top, 0, 0);

 // Write the content to the document
 data.Go();

 pdfStamper.FormFlattening = true;
 pdfStamper.Close();
 pdfStamper.Dispose();