logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

New Topic Post Reply
Options
Go to last post Go to first unread
claudiu  
#1 Posted : Monday, July 15, 2019 1:50:14 PM(UTC)
Quote
claudiu

Rank: Newbie

Groups: Registered
Joined: 6/6/2019(UTC)
Posts: 5
Canada

Thanks: 2 times
Hello,

I have multiple documents with signature fields and my requirement is to merge the documents into one file before it is sent to signing. My problem is that after merge, my final document does not have the signature boxes. The merging is done by creating a new document and using ImportPages to concatenate the documents:

Code:

                var mergedPdf = PdfDocument.CreateNew();
                int bookmarkIndex = 0;
                foreach (var d in docs)
                {
                    var pass = CipherHelper.Decrypt<RijndaelManaged>(d.PASSWORD, ConfigHelper.Secret, ConfigHelper.Salt);
                    var tmpDoc = PdfDocument.Load(d.CONTENT,null, pass);
                    int index = mergedPdf.Pages.Count;
                    mergedPdf.Pages.ImportPages(tmpDoc, null, index);
                    if (mergedPdf.Pages.Count > 0)
                    {
                        mergedPdf.Bookmarks.InsertAt(bookmarkIndex, d.FILENAME, mergedPdf.Pages[index]);
                        bookmarkIndex++;
                    }
                }
 


Is there any way to fix this issue or an alternative merging method?

Thank You!
Paul Rayman  
#2 Posted : Tuesday, July 16, 2019 11:11:38 PM(UTC)
Quote
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 895

Thanks: 3 times
Was thanked: 109 time(s) in 106 post(s)
This happens because the AcroForm dictionary is not imported.
You can import this dictionary yourself. For example, like this:

Usage
Code:
var mergedPdf = PdfDocument.CreateNew();
var tmpDoc = PdfDocument.Load(@"e:\11\test.pdf");
mergedPdf.Pages.ImportPages(tmpDoc, null, 0);
ImportAcroForm(tmpDoc, mergedPdf);
mergedPdf.Save(@"e:\11\signew.pdf", Patagames.Pdf.Enums.SaveFlags.NoIncremental);


and ImportAcroForm
Code:
private void ImportAcroForm(PdfDocument srcDoc, PdfDocument dstDoc)
{
    if (!srcDoc.Root.ContainsKey("AcroForm"))
        return;

    var list = PdfIndirectList.FromPdfDocument(dstDoc);
    PdfTypeDictionary acroForm = srcDoc.Root["AcroForm"].As<PdfTypeDictionary>().Clone() as PdfTypeDictionary;
    list.Add(acroForm);
    dstDoc.Root.SetIndirectAt("AcroForm", list, acroForm);

    if (acroForm.ContainsKey("Fields"))
        acroForm["Fields"].As<PdfTypeArray>().Clear();
    else
        acroForm["Fields"] = PdfTypeArray.Create();

    foreach (var page in dstDoc.Pages)
    {
        if (page.Annots == null)
            continue;
        foreach(var annot in page.Annots)
        {
            if (annot is PdfWidgetAnnotation)
                acroForm["Fields"].As<PdfTypeArray>().AddIndirect(list, annot.Dictionary.ObjectNumber);
        }
    }
}


The correct structure of the document should be like in the image below. The code forms such a structure by cloning the AcroForm dictionary and by re-forms the array of fields with actual object numbers.

111.png
thanks 1 user thanked Paul Rayman for this useful post.
claudiu on 7/17/2019(UTC)
claudiu  
#3 Posted : Wednesday, July 17, 2019 6:58:40 PM(UTC)
Quote
claudiu

Rank: Newbie

Groups: Registered
Joined: 6/6/2019(UTC)
Posts: 5
Canada

Thanks: 2 times
Thanks Paul, it works a treat!
ryanthomas03  
#4 Posted : Friday, October 18, 2019 1:26:11 PM(UTC)
Quote
ryanthomas03

Rank: Newbie

Groups: Registered
Joined: 9/5/2019(UTC)
Posts: 3
United States

There are some problems with this logic as well as with the ImportPages(..) logic which prevents copying form fields that are not flat / not top level only.

1st: ImportPages(..) does not appear to properly handle copying / updating the 'Parent' and 'Kids' references from the source document to the destination document.

Using an example source document with:


Code:

"AcroForm" -> "Fields" -> [ 
    { "DA": ..., "FT": "Tx", "Kids": [ {Kid1, Kid2}], "T": "Field1" },
    { "DA": ..., "FT": "Tx", "Kids": [ {Kid3, Kid4}], "T": "Field2" },
    { "AP": .., "DA": .., "F": ..,  "FT": "Tx", "MK": .., "P", .., "Rect": .., "Subtype": .., "T": "Field3", ... }
]


There are essentially 5 annotation widgets (kid1, kid2, kid3, kid4, and Field3).

After calling ImportPages(..) kid1, kid2, kid3, kid4 and field3 will all be cloned and copied to the new document.

But ClonedKid1.Parent, ClonedKid2.Parent, ClonedKid3.Parent, and ClonedKid4.Parent will all still point back to the original Field1 and Field2 objects which were never cloned to the new document. Additionally Field1.Kids and Field2.Kids will point to the original document Kid1, Kid2, Kid3, Kid4, not the cloned ones.

In addition to the references pointing to the old document's objects, the ImportAcroForm(..) logic you provided copies the annotations to the fields array is if they're all top level. Given the above input 'fields' you would end up with a copied fields array that looks like:

Code:

"AcroForm (NewDocument)" -> "Fields (NewDocument)" -> [ 
    { ClonedKid1 },
    { ClonedKid2 },
    { ClonedKid3 },
    { ClonedKid4 },
    { Cloned Field3 }
]


I wrote a routine to take a stab at cloning/copying the parents to the new document and ensuring the field structure is preserved. It works up until the point I attempt to save the new pdf, then the execution environment crashes with an underlying win32 exception. I'm not sure why.

If I attempt to save to a file it outputs a file before crashing and the output file appears to be valid (at least valid enough that I can then re-open it as a pdf and/or inspect the fields and see that the structure was preserved).

The attempt is contained in this gist:
https://gist.github.com/...893a335ba99aca8cbd915822

Edited by user Friday, October 18, 2019 1:27:05 PM(UTC)  | Reason: Not specified

claudiu  
#5 Posted : Friday, December 13, 2019 3:54:55 PM(UTC)
Quote
claudiu

Rank: Newbie

Groups: Registered
Joined: 6/6/2019(UTC)
Posts: 5
Canada

Thanks: 2 times
Is there a way to change the name of a field?
Sometime when I merge pdf documents, I end up with signature fields with the same name. This will mess with signing software.

Thanks!
Paul Rayman  
#6 Posted : Monday, December 16, 2019 12:45:55 AM(UTC)
Quote
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 895

Thanks: 3 times
Was thanked: 109 time(s) in 106 post(s)
Try to change "T" (or TU ot TM) entry in the field's dictionary.

from PDF specification:

T - text string - (Optional) - The partial field name (see “Field Names,” below; see also implementation notes 116 and 117 in Appendix H).

TU - text string - (Optional; PDF 1.3) - An alternate field name to be used in place of the actual field name wherever the field must be identified in the user interface (such as in error or status messages referring to the field). This text is also useful when extracting the document’s contents in support of accessibility to users with disabilities or for other purposes (see Section 10.8.2, “Alternate Descriptions”).

TM - text string - (Optional; PDF 1.3) - The mapping name to be used when exporting interactive form field data from the document

Field Names

The T entry in the field dictionary (see Table 8.69 on page 675) holds a text string
defining the field’s partial field name. The fully qualified field name is not explicitly defined but is constructed from the partial field names of the field and all of its ancestors. For a field with no parent, the partial and fully qualified names are the same. For a field that is the child of another field, the fully qualified name is formed by appending the child field’s partial name to the parent’s fully qualified name, separated by a period (.):

parent’s_full_name.child’s_partial_name


Quick Reply Show Quick Reply
Users browsing this topic
New Topic Post Reply
Forum Jump  
You can post new topics in this forum.
You can reply to topics in this forum.
You can delete your posts in this forum.
You can edit your posts in this forum.
You cannot create polls in this forum.
You can vote in polls in this forum.