Search code examples
pdfannotationsitextmailmerge

Copy annotations


I have a source PDF with some Free Text Annotations.

I would like to perform a mail merge like function on PDF. I would like to make a copy of the PDF and replace the Free Text Annotation based on some text replacement method.

For simplicity, I have a program that takes the annotations and add "LHC" behind it. Alas, the copy works, but the annotations remains unchanged.

I would have tried to use PdfAnnotation however, I am unsure how to convert from the PdfDictionary to PdfAnnotation

See my code below

string oldFile = "C:\\Temp\\oldFile.pdf";
string newFile = "C:\\Temp\\newFile.pdf";

// open the reader
PdfReader reader = new PdfReader(oldFile);
Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);

// open the writer
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfCopy writer = new PdfCopy(document,fs);
document.Open();

// the pdf content
PdfContentByte cb = writer.DirectContent;

// adding Free Text Annotation 

for (int pg = 1; pg < reader.NumberOfPages; pg++)
{
    PdfDictionary pageDict = reader.GetPageN(pg);
    PdfArray annotArray = pageDict.GetAsArray(PdfName.ANNOTS);
    for (int i = 0; i < annotArray.Size; ++i)
    {
        PdfDictionary curAnnot = annotArray.GetAsDict(i);
        PdfName contents = new PdfName("Contents");
        PdfString str = curAnnot.GetAsString(contents);
        String newString = str.ToString() + "LHC";
        curAnnot.Remove(contents);
        curAnnot.Put(contents, new PdfString(newString));
    }

    PdfImportedPage page = writer.GetImportedPage(reader, pg);
    // PdfImportedPage pageOut = writer.destinationPdfReader(reader, pg);
    //cb.AddTemplate(page, 0, 0);
    writer.AddPage(page);
    PdfAnnotation annot = new PdfAnnotation(writer, new Rectangle(0, 0));
    writer.AddAnnotation(annot);
}

document.Close();
fs.Close();
writer.Close();
reader.Close();

Solution

  • References: http://itextsharp.10939.n7.nabble.com/How-to-edit-annotations-td3352.html

    (There is another link in stackoverflow, that I can't find, when I find it I will add it here)

    The steps:

    Step 1. Create a stamper from a reader.

    Step 2. Read all the annotations

    Step 3. Delete a set of keys and as a fallback any dictionary items

    You now have performed an edit/copy of the annotation and changed the values.

    The following is the code:

    // Step 1. Create the stamper

            string oldFile = "C:\\Temp\\oldFile.pdf";
            string newFile = "C:\\Temp\\newFile.pdf";
            // open the reader
            PdfReader reader = new PdfReader(oldFile);
            Rectangle size = reader.GetPageSizeWithRotation(1);
            Document document = new Document(size);
    
            // open the writer
    
            // remember to set the page size before opening document
            // otherwise the page is already set.
            /* chapter02/HelloWorldMetadata.java */
            document.Open();
    
            // the pdf content
            // cb does not work with stamper 
    
    
            // create the new pagez and add it to the pdf
            // this segment of code is meant for writer
            FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.ReadWrite);
    
    
            PdfStamper writer = new PdfStamper(reader, fs, reader.PdfVersion, false);
    
            for (int pg = 1; pg < reader.NumberOfPages; pg++)
            {
    
                // taken from http://itextsharp.10939.n7.nabble.com/How-to-edit-annotations-td3352.html
    
                PdfDictionary pagedic = reader.GetPageN(pg);
                PdfArray annotarray = (PdfArray)PdfReader.GetPdfObject(pagedic.Get(PdfName.ANNOTS));
    
                if (annotarray == null || annotarray.Size == 0)
                    continue;
    

    // step 2. read all the annotations

                foreach (PdfIndirectReference annot in annotarray.ArrayList)
                {
                    PdfDictionary annotationDic = (PdfDictionary)PdfReader.GetPdfObject(annot);
                    PdfName subType = (PdfName)annotationDic.Get(PdfName.SUBTYPE);
                    if (subType.Equals(PdfName.TEXT) || subType.Equals(PdfName.FREETEXT))
                    {
    

    // 3. Change values of different properties of a certain annotation and delete a few keys & dictionaries

                        annotationDic.Put(PdfName.CONTENTS, new PdfString("These are changed contents", PdfObject.TEXT_UNICODE));
                    }
                    PdfString contents = annotationDic.GetAsString(PdfName.CONTENTS);
                    if (contents != null)
                    {
                        String value = contents.ToString();
                        annotationDic.Put(PdfName.CONTENTS, new PdfString(value));
                        annotationDic.Remove(PdfName.AP);
                        List<PdfName> tobeDel = new List<PdfName>();
                        foreach (PdfName key in annotationDic.Keys)
                        {
                            if (key.CompareTo(PdfName.AP) == 0 ||
                                key.CompareTo(PdfName.RC) == 0 ||
                                annotationDic.Get(key).IsDictionary())
                            {
                                tobeDel.Add(key);
                            }
                        }
                        foreach (PdfName key in tobeDel)
                        {
                            annotationDic.Remove(key);
                        }
                    }
                    writer.MarkUsed(annotationDic);
    
                }
                if ((pg + 1) < reader.NumberOfPages)
                {
                    document.NewPage();
                }
            }
    
    
            // close the streams and voilá the file should be changed :)
    
            writer.Close();
            reader.Close();