private void ImportAcroField(PdfPage page, PdfPage importPage, PdfAcroForm localForm, PdfImportedObjectTable importedObjectTable, PdfAcroField fieldObj, bool isChild) { if (fieldObj != null) { PdfDictionary importedObject; if (!importedObjectTable.Contains(fieldObj.ObjectID)) { // Do not use PdfObject.DeepCopyClosure as that would also create new Pages when encountering the "/P" Entry ! importedObject = ImportClosure(importedObjectTable, _document, fieldObj) as PdfDictionary; } else { importedObject = importedObjectTable[fieldObj.ObjectID].Value as PdfDictionary; } Debug.Assert(importedObject != null, "Imported AcroField is null"); if (importedObject != null) { var name = importedObject is PdfAcroField ? ((PdfAcroField)importedObject).FullyQualifiedName : "NoName"; Debug.WriteLine(String.Format("Importing {0} '{1}' ({2})", importedObject.GetType().Name, name, importedObject.ObjectID)); if (importedObject.Elements.ContainsKey("/P")) { var fieldPage = importedObject.Elements.GetObject(PdfAnnotation.Keys.Page); Debug.Assert(_document._irefTable.Contains(fieldPage.ObjectID), "Page of imported field should exist in current document"); } if (!isChild && !IsInArray(localForm.Fields, importedObject)) { localForm.Fields.Elements.Add(importedObject); } } } }
private PdfReference FixDocumentRef(PdfItem objItem, PdfImportedObjectTable importedObjectTable) { if (objItem == null) { return(null); } var obj = objItem as PdfObject; if (obj != null) { obj._document = _document; } var dict = obj as PdfDictionary; if (dict != null) { foreach (var key in dict.Elements.KeyNames) { var r = FixDocumentRef(dict.Elements[key], importedObjectTable); if (r != null) { dict.Elements.SetReference(key.Value, r.Value); } } } var array = obj as PdfArray; if (array != null) { for (var i = 0; i < array.Elements.Count; i++) { var r = FixDocumentRef(array.Elements[i], importedObjectTable); if (r != null) { array.Elements[i] = r; } } } var reference = objItem as PdfReference; if (reference != null && reference.Document != _document) { if (importedObjectTable.Contains(reference.ObjectID)) { return(importedObjectTable[reference.ObjectID]); } var value = ImportClosure(importedObjectTable, _document, reference.Value); Debug.Assert(value.Reference != null); return(value.Reference); } return(null); }
///// <summary> ///// Imports an object and its transitive closure to the specified document. ///// </summary> /// <param name="importedObjectTable">The imported object table of the owner for the external document.</param> /// <param name="owner">The document that owns the cloned objects.</param> /// <param name="externalObject">The root object to be cloned.</param> /// <returns>The clone of the root object</returns> internal static PdfObject ImportClosure(PdfImportedObjectTable importedObjectTable, PdfDocument owner, PdfObject externalObject) { Debug.Assert(ReferenceEquals(importedObjectTable.Owner, owner), "importedObjectTable does not belong to the owner."); Debug.Assert(ReferenceEquals(importedObjectTable.ExternalDocument, externalObject.Owner), "The ExternalDocument of the importedObjectTable does not belong to the owner of object to be imported."); // Get transitive closure of external object. PdfObject[] elements = externalObject.Owner.Internals.GetClosure(externalObject); int count = elements.Length; #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(elements[idx].XRef != null); Debug.Assert(elements[idx].XRef.Document != null); Debug.Assert(elements[idx].Document != null); if (elements[idx].ObjectID.ObjectNumber == 12) { GetType(); } } #endif // 1st loop. Already imported objects are reused and new ones are cloned. for (int idx = 0; idx < count; idx++) { PdfObject obj = elements[idx]; Debug.Assert(!ReferenceEquals(obj.Owner, owner)); if (importedObjectTable.Contains(obj.ObjectID)) { #if DEBUG_ if (obj.ObjectID.ObjectNumber == 5894) { obj.GetType(); } #endif // Case: External object was already imported. PdfReference iref = importedObjectTable[obj.ObjectID]; Debug.Assert(iref != null); Debug.Assert(iref.Value != null); Debug.Assert(iref.Document == owner); // Replace external object by the already cloned counterpart. elements[idx] = iref.Value; } else { // Case: External object was not yet imported earlier and must be cloned. PdfObject clone = obj.Clone(); Debug.Assert(clone.Reference == null); clone.Document = owner; if (obj.Reference != null) { // Case: The cloned object was an indirect object. // Add clone to new owner document. owner._irefTable.Add(clone); Debug.Assert(clone.Reference != null); // Save an association from old object identifier to new iref. importedObjectTable.Add(obj.ObjectID, clone.Reference); } else { // Case: The cloned object was a direct object. // Only the root object can be a direct object. Debug.Assert(idx == 0); } // Replace external object by its clone. elements[idx] = clone; } } #if DEBUG_ for (int idx = 0; idx < count; idx++) { //Debug.Assert(elements[idx].Reference != null); //Debug.Assert(elements[idx].Reference.Document != null); Debug.Assert(elements[idx].IsIndirect == false); Debug.Assert(elements[idx].Owner != null); //if (elements[idx].ObjectID.ObjectNumber == 12) // GetType(); } #endif // 2nd loop. Fix up indirect references that still refers to the external document. for (int idx = 0; idx < count; idx++) { PdfObject obj = elements[idx]; Debug.Assert(owner != null); FixUpObject(importedObjectTable, importedObjectTable.Owner, obj); } // Return the imported root object. return(elements[0]); }
private void FixAcroFields(PdfAcroField.PdfAcroFieldCollection formFields, PdfImportedObjectTable importedObjectTable) { for (var i = 0; i < formFields.Elements.Count; i++) { var field = formFields[i]; if (field.Owner != _document) { field._document = _document; } field.Reference.Document = _document; if (field.ObjectID.IsEmpty || !_document._irefTable.Contains(field.ObjectID)) { _document._irefTable.Add(field); } //// fix the /P entry for Field-Annotations //var fieldPage = field.Elements.GetDictionary(PdfAcroField.Keys.Page); //if (fieldPage != null && fieldPage.Owner != _document) //{ // var importedPage = importedObjectTable.Contains(fieldPage.ObjectID) ? importedObjectTable[fieldPage.ObjectID] : null; // if (importedPage != null) // { // field.Elements.SetReference(PdfAcroField.Keys.Page, importedPage.Value); // Debug.WriteLine(String.Format("Fixed page of '{0}' ({1}) -> {2} = {3}", field.FullyQualifiedName, field.ObjectID, fieldPage.ObjectID, importedPage.ObjectID)); // } // else // Debug.WriteLine(String.Format("Can't fix page of '{0}' ({1}), imported page not found", field.FullyQualifiedName, field.ObjectID)); //} // Annotations are "partly" imported, we need to fix the /P entry for (var a = 0; a < field.Annotations.Elements.Count; a++) { var widget = field.Annotations.Elements[a]; if (widget != null) { // the owner has to be fixed as well... // Note: it was observed that some objects referenced by the widget were still owned by the imported document, but that seems to be fixed on saving... if (widget.Owner != _document) { if (_document._irefTable.Contains(widget.ObjectID)) { widget._document = _document; widget.Reference.Document = _document; if (!_document._irefTable.Contains(widget.ObjectID)) { _document._irefTable.Add(widget); } } else { // this was never needed during debugging, we leave it here just in case... var importedWidget = ImportClosure(importedObjectTable, _document, widget) as PdfDictionary; if (importedWidget != null) { widget = new PdfWidgetAnnotation(importedWidget); } } FixDocumentRef(widget, importedObjectTable); } var widgetPage = widget.Page; if (widgetPage != null && widgetPage.Owner != _document) { var importedPage = importedObjectTable.Contains(widgetPage.ObjectID) ? importedObjectTable[widgetPage.ObjectID] : null; if (importedPage != null) { widget.Elements.SetReference(PdfAnnotation.Keys.Page, importedPage.Value); Debug.WriteLine(String.Format("Fixed page of Widget '{0}' ({1}) -> {2} = {3}", field.FullyQualifiedName, field.ObjectID, widgetPage.ObjectID, importedPage.ObjectID)); var ip = importedPage.Value as PdfPage; // the widget is a PdfWidgetAnnotation, but the "real" object may be something else (e.g. a PdfGenericField), so we check the referenced object instead if (ip != null && !ip.Annotations.Elements.Contains(widget.Reference)) { ip.Annotations.Elements.Add(widget.Reference.Value); } } } else if (widgetPage is PdfPage) { // add widget to the pages' annotations if not already present if (!((PdfPage)widgetPage).Annotations.Elements.Contains(widget.Reference)) { ((PdfPage)widgetPage).Annotations.Elements.Add(widget); } } } } if (field.HasKids) { FixAcroFields(field.Fields, importedObjectTable); } } }