How to prevent replacement annotation from changing position and text size? (x-post StackOverflow)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

How to prevent replacement annotation from changing position and text size? (x-post StackOverflow)

sigil
Link to StackOverflow post here

I'm using iTextSharp to replace Typewriter annotations with Textboxes that have the same content and position, but some of the resulting Textboxes end up in different positions with different text sizes, despite seemingly having exactly the same data in their hashMap.

The problem is that when I create these new annotations on this sample PDF, and then view the PDF in Adobe Acrobat XI, the new Textboxes have the following problems:

* They have moved from their original positions (adjacent to the arrows) to lower on the page

* The text has changed in size

* There is no Properties available when the new Textbox is right-clicked

I suspect that all 3 problems are due to a single underlying issue with how I'm creating the new Textbox.

When I check the /Rect key in the hashMap for annot, it has the same rectangle coordinates in the same order as the original freeTextAnnot, so I don't understand why some of the annotations end up displaced.


Here's my code for creating the new Textbox with the existing Typewriter annotation data.  Note that you'll need to set inputPath and outputPath to the actual location of the PDF and its destination path:

(sorry, I don't know the markdown for a code block)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using iTextSharp;
    using iTextSharp.text.pdf;
    using System.IO;
   
    namespace PDFConverterTester
    {
        public class PdfModifierTester
        {
            public void testWithPaths()
            {
                //set to location of test PDF
                string inputPath = @"C:\InputPath\Before Conversion Dummy.pdf";
                //set to destination of new PDF
                string outputPath = @"C:\OutputPath\Before Conversion Dummy.pdf";
                test(inputPath, outputPath);
            }
   
            public void test(string inputPath, string outputPath)
            {
                PdfReader pdfReader = new PdfReader(inputPath);
                PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(outputPath, FileMode.Create));
                //get the PdfDictionary of the 1st page
                PdfDictionary pageDict = pdfReader.GetPageN(1);
                //get annotation array
                PdfArray annotArray = pageDict.GetAsArray(PdfName.ANNOTS);
                //iterate through annotation array
                int size = annotArray.Size;
                for (int i = size - 1; i >= 0; i--)
                {
                    PdfDictionary dict = annotArray.GetAsDict(i);
                    PdfName ITName = dict.GetAsName(new PdfName("IT"));
                    if (ITName != null)
                    {
                        if (ITName.Equals(new PdfName("FreeTextTypewriter")))
                        {
                            PdfAnnotation annot = copyToNewAnnotation_SSCCE(dict,pdfStamper);
                            pdfStamper.AddAnnotation(annot, 1);
                            annotArray.Remove(i);
                        }
                    }
                }
                pdfStamper.Close();
                pdfReader.Close();
            }
   
            private PdfAnnotation copyToNewAnnotation_SSCCE(PdfDictionary freeTextAnnot,PdfStamper pdfStamper)
            {
   
                //need Rectangle for CreateFreeText()
                iTextSharp.text.Rectangle rect;
                PdfArray rectArray = freeTextAnnot.GetAsArray(PdfName.RECT);
                if (rectArray == null)
                {
                    rect = null;
                }
                else
                {
                    rect = new iTextSharp.text.Rectangle(getFloat(rectArray, 0),
                                                                              getFloat(rectArray, 1),
                                                                              getFloat(rectArray, 2),
                                                                              getFloat(rectArray, 3));
                }
                //create new annotation
                PdfContentByte pcb = new PdfContentByte(pdfStamper.Writer);
                PdfAnnotation annot = PdfAnnotation.CreateFreeText(pdfStamper.Writer, rect, "", pcb);
                //make array of all possible PdfName keys in dictionary for freeTextAnnot
                string pdfNames = "AP,BS,C,CA,CL,CONTENTS,CREATIONDATE,DA,DS,F,IT,LE,M,NM,P,POPUP,Q,RC,RD,ROTATE,SUBJ,SUBTYPE,T,TYPE";
                string[] pdfNameArray = pdfNames.Split(',');
                //iterate through key array copying key-value pairs to new annotation
                foreach (string pdfName in pdfNameArray)
                {
                    //get value for this PdfName
                    PdfName key = new PdfName(pdfName);
                    PdfObject obj = freeTextAnnot.Get(key);
                    //if returned value is null, maybe key is case-sensitive
                    if (obj == null)
                    {
                        //try with first letter only capitalized, e.g. "Contents" instead of "CONTENTS"
                        string firstCappdfName = char.ToUpper(pdfName[0]) + pdfName.Substring(1);
                        key = new PdfName(firstCappdfName);
                        obj = freeTextAnnot.Get(key);
                    }
                    //set key-value pair in new annotation
                    annot.Put(key, obj);
                }
                //change annotation type to Textbox
                annot.Put(PdfName.SUBTYPE, PdfName.FREETEXT);
                annot.Put(new PdfName("Subj"), new PdfString("Textbox"));
   
                //set a default blank border
                annot.Put(PdfName.BORDER, new PdfBorderArray(0, 0, 0));
   
                return annot;
   
   
            }
   
            private float getFloat(PdfArray arr, int index)
            {
                return float.Parse(arr[index].ToString());
            }
        }
    }