/// <summary> /// Helper function for ImportExternalPage. /// </summary> void CloneElement(PdfPage page, PdfPage importPage, string key, bool deepcopy) { Debug.Assert(page != null); Debug.Assert(page.Owner == _document); Debug.Assert(importPage.Owner != null); Debug.Assert(importPage.Owner != _document); PdfItem item = importPage.Elements[key]; if (item != null) { PdfImportedObjectTable importedObjectTable = null; if (!deepcopy) { importedObjectTable = Owner.FormTable.GetImportedObjectTable(importPage); } // The item can be indirect. If so, replace it by its value. if (item is PdfReference) { item = ((PdfReference)item).Value; } if (item is PdfObject) { PdfObject root = (PdfObject)item; if (deepcopy) { Debug.Assert(root.Owner != null, "See 'else' case for details"); root = DeepCopyClosure(_document, root); } else { // The owner can be null if the item is not a reference. if (root.Owner == null) { root.Document = importPage.Owner; } root = ImportClosure(importedObjectTable, page.Owner, root); } if (root.Reference == null) { page.Elements[key] = root; } else { page.Elements[key] = root.Reference; } } else { // Simple items are just cloned. page.Elements[key] = item.Clone(); } } }
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> /// Replace all indirect references to external objects by their cloned counterparts /// owned by the importer document. /// </summary> static void FixUpObject(PdfImportedObjectTable iot, PdfDocument owner, PdfObject value) { Debug.Assert(ReferenceEquals(iot.Owner, owner)); PdfDictionary dict; PdfArray array; if ((dict = value as PdfDictionary) != null) { // Case: The object is a dictionary. // Set document for cloned direct objects. if (dict.Owner == null) { // If the dictionary has not yet an owner set the owner to the importing document. dict.Document = owner; } else { // If the dictionary already has an owner it must be the importing document. Debug.Assert(dict.Owner == owner); } // Search for indirect references in all dictionary elements. PdfName[] names = dict.Elements.KeyNames; foreach (PdfName name in names) { PdfItem item = dict.Elements[name]; Debug.Assert(item != null, "A dictionary element cannot be null."); // Is item an iref? PdfReference iref = item as PdfReference; if (iref != null) { // Case: The item is a reference. // Does the iref already belongs to the new owner? if (iref.Document == owner) { // Yes: fine. Happens when an already cloned object is reused. continue; } //Debug.Assert(iref.Document == iot.Document); // No: Replace with iref of cloned object. PdfReference newXRef = iot[iref.ObjectID]; // TODO: Explain this line of code in all details. Debug.Assert(newXRef != null); Debug.Assert(newXRef.Document == owner); dict.Elements[name] = newXRef; } else { // Case: The item is not a reference. // If item is an object recursively fix its inner items. PdfObject pdfObject = item as PdfObject; if (pdfObject != null) { // Fix up inner objects, i.e. recursively walk down the object tree. FixUpObject(iot, owner, pdfObject); } else { // The item is something else, e.g. a name. // Nothing to do. // ...but let's double check this case in DEBUG build. DebugCheckNonObjects(item); } } } } else if ((array = value as PdfArray) != null) { // Case: The object is an array. // Set document for cloned direct objects. if (array.Owner == null) { // If the array has not yet an owner set the owner to the importing document. array.Document = owner; } else { // If the array already has an owner it must be the importing document. Debug.Assert(array.Owner == owner); } // Search for indirect references in all array elements. int count = array.Elements.Count; for (int idx = 0; idx < count; idx++) { PdfItem item = array.Elements[idx]; Debug.Assert(item != null, "An array element cannot be null."); // Is item an iref? PdfReference iref = item as PdfReference; if (iref != null) { // Case: The item is a reference. // Does the iref already belongs to the owner? if (iref.Document == owner) { // Yes: fine. Happens when an already cloned object is reused. continue; } // No: replace with iref of cloned object. Debug.Assert(iref.Document == iot.ExternalDocument); PdfReference newXRef = iot[iref.ObjectID]; Debug.Assert(newXRef != null); Debug.Assert(newXRef.Document == owner); array.Elements[idx] = newXRef; } else { // Case: The item is not a reference. // If item is an object recursively fix its inner items. PdfObject pdfObject = item as PdfObject; if (pdfObject != null) { // Fix up inner objects, i.e. recursively walk down the object tree. FixUpObject(iot, owner, pdfObject); } else { // The item is something else, e.g. a name. // Nothing to do. // ...but let's double check this case in DEBUG build. DebugCheckNonObjects(item); } } } } else { // Case: The item is some other indirect object. // Indirect integers, booleans, etc. are allowed, but PDFsharp do not create them. // If such objects occur in imported PDF files from other producers, nothing more is to do. // The owner was already set, which is double checked by the assertions below. if (value is PdfNameObject || value is PdfStringObject || value is PdfBooleanObject || value is PdfIntegerObject || value is PdfNumberObject) { Debug.Assert(value.IsIndirect); Debug.Assert(value.Owner == owner); } else { Debug.Assert(false, "Should not come here. Object is neither a dictionary nor an array."); } } }
///// <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]); }
///// <summary> ///// Creates a deep copy of the specified value and its transitive closure and adds the ///// new objects to the specified owner document. ///// </summary> /// <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 DeepCopyClosure(PdfDocument owner, PdfObject externalObject) { // Get transitive closure. 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. Replace all objects by their clones. PdfImportedObjectTable iot = new PdfImportedObjectTable(owner, externalObject.Owner); for (int idx = 0; idx < count; idx++) { PdfObject obj = elements[idx]; 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); // The clone gets an iref by adding it to its new owner. Debug.Assert(clone.Reference != null); // Save an association from old object identifier to new iref. iot.Add(obj.ObjectID, clone.Reference); } else { // Case: The cloned object was an 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]._iref != null); Debug.Assert(elements[idx]._iref.Document != null); Debug.Assert(resources[idx].Document != null); if (elements[idx].ObjectID.ObjectNumber == 12) { GetType(); } } #endif // 2nd loop. Fix up all indirect references that still refers to the import document. for (int idx = 0; idx < count; idx++) { PdfObject obj = elements[idx]; Debug.Assert(obj.Owner == owner); FixUpObject(iot, owner, obj); } // Return the clone of the former root object. return(elements[0]); }
/// <summary> /// Inserts pages of the specified document into this document. /// </summary> /// <param name="index">The index in this document where to insert the page .</param> /// <param name="document">The document to be inserted.</param> /// <param name="startIndex">The index of the first page to be inserted.</param> /// <param name="pageCount">The number of pages to be inserted.</param> public void InsertRange(int index, PdfDocument document, int startIndex, int pageCount) { if (document == null) { throw new ArgumentNullException("document"); } if (index < 0 || index > Count) { throw new ArgumentOutOfRangeException("index", "Argument 'index' out of range."); } int importDocumentPageCount = document.PageCount; if (startIndex < 0 || startIndex + pageCount > importDocumentPageCount) { throw new ArgumentOutOfRangeException("startIndex", "Argument 'startIndex' out of range."); } if (pageCount > importDocumentPageCount) { throw new ArgumentOutOfRangeException("pageCount", "Argument 'pageCount' out of range."); } PdfPage[] insertPages = new PdfPage[pageCount]; PdfPage[] importPages = new PdfPage[pageCount]; // 1st create all new pages. for (int idx = 0, insertIndex = index, importIndex = startIndex; importIndex < startIndex + pageCount; idx++, insertIndex++, importIndex++) { PdfPage importPage = document.Pages[importIndex]; PdfPage page = ImportExternalPage(importPage); insertPages[idx] = page; importPages[idx] = importPage; Owner._irefTable.Add(page); // Add page substitute to importedObjectTable. PdfImportedObjectTable importedObjectTable = Owner.FormTable.GetImportedObjectTable(importPage); importedObjectTable.Add(importPage.ObjectID, page.Reference); PagesArray.Elements.Insert(insertIndex, page.Reference); if (Owner.Settings.TrimMargins.AreSet) { page.TrimMargins = Owner.Settings.TrimMargins; } } Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); // 2nd copy link annotations that are in the range of the imported pages. for (int idx = 0, importIndex = startIndex; importIndex < startIndex + pageCount; idx++, importIndex++) { PdfPage importPage = document.Pages[importIndex]; PdfPage page = insertPages[idx]; // Get annotations. PdfArray annots = importPage.Elements.GetArray(PdfPage.Keys.Annots); if (annots != null) { PdfAnnotations annotations = new PdfAnnotations(Owner); // Loop through annotations. int count = annots.Elements.Count; for (int idxAnnotation = 0; idxAnnotation < count; idxAnnotation++) { PdfDictionary annot = annots.Elements.GetDictionary(idxAnnotation); if (annot != null) { string subtype = annot.Elements.GetString(PdfAnnotation.Keys.Subtype); if (subtype == "/Link") { bool addAnnotation = false; PdfLinkAnnotation newAnnotation = new PdfLinkAnnotation(Owner); PdfName[] importAnnotationKeyNames = annot.Elements.KeyNames; foreach (PdfName pdfItem in importAnnotationKeyNames) { PdfItem impItem; switch (pdfItem.Value) { case "/BS": newAnnotation.Elements.Add("/BS", new PdfLiteral("<</W 0>>")); break; case "/F": // /F 4 impItem = annot.Elements.GetValue("/F"); Debug.Assert(impItem is PdfInteger); newAnnotation.Elements.Add("/F", impItem.Clone()); break; case "/Rect": // /Rect [68.6 681.08 145.71 702.53] impItem = annot.Elements.GetValue("/Rect"); Debug.Assert(impItem is PdfArray); newAnnotation.Elements.Add("/Rect", impItem.Clone()); break; case "/StructParent": // /StructParent 3 impItem = annot.Elements.GetValue("/StructParent"); Debug.Assert(impItem is PdfInteger); newAnnotation.Elements.Add("/StructParent", impItem.Clone()); break; case "/Subtype": // Already set. break; case "/Dest": // /Dest [30 0 R /XYZ 68 771 0] impItem = annot.Elements.GetValue("/Dest"); impItem = impItem.Clone(); // Is value an array with 5 elements where the first one is an iref? PdfArray destArray = impItem as PdfArray; if (destArray != null && destArray.Elements.Count == 5) { PdfReference iref = destArray.Elements[0] as PdfReference; if (iref != null) { iref = RemapReference(insertPages, importPages, iref); if (iref != null) { destArray.Elements[0] = iref; newAnnotation.Elements.Add("/Dest", destArray); addAnnotation = true; } } } break; default: #if DEBUG_ Debug - Break.Break(true); #endif break; } } // Add newAnnotations only it points to an imported page. if (addAnnotation) { annotations.Add(newAnnotation); } } } } // At least one link annotation found? if (annotations.Count > 0) { //Owner._irefTable.Add(annotations); page.Elements.Add(PdfPage.Keys.Annots, annotations); } } } }
/// <summary> /// Inserts the specified PdfPage at the specified position to this document and maybe returns a new PdfPage object. /// The value returned is a new object if the inserted page comes from a foreign document. /// </summary> public PdfPage Insert(int index, PdfPage page) { if (page == null) { throw new ArgumentNullException("page"); } // Is the page already owned by this document? if (page.Owner == Owner) { // Case: Page is first removed and than inserted again, maybe at another position. int count = Count; // Check if page is not already part of the document. for (int idx = 0; idx < count; idx++) { if (ReferenceEquals(this[idx], page)) { throw new InvalidOperationException(PSSR.MultiplePageInsert); } } // TODO: check this case // Because the owner of the inserted page is this document we assume that the page was former part of it // and it is therefore well-defined. Owner._irefTable.Add(page); Debug.Assert(page.Owner == Owner); // Insert page in array. PagesArray.Elements.Insert(index, page.Reference); // Update page count. Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); return(page); } // All new page insertions come here. if (page.Owner == null) { // Case: New page was newly created and inserted now. page.Document = Owner; Owner._irefTable.Add(page); Debug.Assert(page.Owner == Owner); PagesArray.Elements.Insert(index, page.Reference); Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); } else { // Case: Page is from an external document -> import it. PdfPage importPage = page; page = ImportExternalPage(importPage); Owner._irefTable.Add(page); // Add page substitute to importedObjectTable. PdfImportedObjectTable importedObjectTable = Owner.FormTable.GetImportedObjectTable(importPage); importedObjectTable.Add(importPage.ObjectID, page.Reference); PagesArray.Elements.Insert(index, page.Reference); Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); PdfAnnotations.FixImportedAnnotation(page); } if (Owner.Settings.TrimMargins.AreSet) { page.TrimMargins = Owner.Settings.TrimMargins; } return(page); }
/// <summary> /// Replace all indirect references to external objects by their cloned counterparts /// owned by the importer document. /// </summary> internal static void FixUpObject(PdfImportedObjectTable iot, PdfDocument owner, PdfObject value) { Debug.Assert(ReferenceEquals(iot.Owner, owner)); PdfDictionary dict; PdfArray array; if ((dict = value as PdfDictionary) != null) { // Set document for cloned direct objects if (dict.Owner == null) { dict.Document = owner; } else { Debug.Assert(dict.Owner == owner); } // Search for indirect references in all keys PdfName[] names = dict.Elements.KeyNames; foreach (PdfName name in names) { PdfItem item = dict.Elements[name]; // Is item an iref? PdfReference iref = item as PdfReference; if (iref != null) { // Does the iref already belongs to the owner? if (iref.Document == owner) { // Yes: fine. Happens when an already cloned object is reused. continue; } else { //Debug.Assert(iref.Document == iot.Document); // No: replace with iref of cloned object PdfReference newXRef = iot[iref.ObjectID]; Debug.Assert(newXRef != null); Debug.Assert(newXRef.Document == owner); dict.Elements[name] = newXRef; } } else if (item is PdfObject) { // Fix up inner objects FixUpObject(iot, owner, (PdfObject)item); } } } else if ((array = value as PdfArray) != null) { // Set document for cloned direct objects if (array.Owner == null) { array.Document = owner; } else { Debug.Assert(array.Owner == owner); } // Search for indirect references in all array elements int count = array.Elements.Count; for (int idx = 0; idx < count; idx++) { PdfItem item = array.Elements[idx]; // Is item an iref? PdfReference iref = item as PdfReference; if (iref != null) { // Does the iref already belongs to the owner? if (iref.Document == owner) { // Yes: fine. Happens when an already cloned object is reused. continue; } else { Debug.Assert(iref.Document == iot.ExternalDocument); // No: replace with iref of cloned object PdfReference newXRef = iot[iref.ObjectID]; Debug.Assert(newXRef != null); Debug.Assert(newXRef.Document == owner); array.Elements[idx] = newXRef; } } else if (item is PdfObject) { // Fix up inner objects FixUpObject(iot, owner, (PdfObject)item); } } } }
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 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); } } }
/// <summary> /// Inserts the specified PdfPage at the specified position to this document and maybe returns a new PdfPage object. /// The value returned is a new object if the inserted page comes from a foreign document. /// </summary> public PdfPage Insert(int index, PdfPage page) { if (page == null) { throw new ArgumentNullException("page"); } // Is the page already owned by this document? if (page.Owner == Owner) { // Case: Page is first removed and than inserted again, maybe at another position. int count = Count; // Check if page is not already part of the document. for (int idx = 0; idx < count; idx++) { if (ReferenceEquals(this[idx], page)) { throw new InvalidOperationException(PSSR.MultiplePageInsert); } } // TODO: check this case // Because the owner of the inserted page is this document we assume that the page was former part of it // and it is therefore well-defined. Owner._irefTable.Add(page); Debug.Assert(page.Owner == Owner); // Insert page in array. PagesArray.Elements.Insert(index, page.Reference); // Update page count. Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); // @PDF/UA: Pages must not be moved. if (_document._uaManager != null) { _document.Events.OnPageAdded(_document, new PageEventArgs { Page = page, PageIndex = index, EventType = PageEventType.Moved }); } return(page); } // All new page insertions come here. if (page.Owner == null) { // Case: New page was newly created and inserted now. page.Document = Owner; Owner._irefTable.Add(page); Debug.Assert(page.Owner == Owner); PagesArray.Elements.Insert(index, page.Reference); Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); // @PDF/UA: Page was created. if (_document._uaManager != null) { _document.Events.OnPageAdded(_document, new PageEventArgs { Page = page, PageIndex = index, EventType = PageEventType.Created }); } } else { #if true // original code // Case: Page is from an external document -> import it. PdfPage importPage = page; page = ImportExternalPage(importPage); Owner._irefTable.Add(page); // Add page substitute to importedObjectTable. PdfImportedObjectTable importedObjectTable = Owner.FormTable.GetImportedObjectTable(importPage); importedObjectTable.Add(importPage.ObjectID, page.Reference); PagesArray.Elements.Insert(index, page.Reference); Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); PdfAnnotations.FixImportedAnnotation(page); #else var externalPage = page; // Case: Page is from an external document -> import it. page = ImportExternalPage(externalPage); Owner._irefTable.Add(page); // Add page substitute to importedObjectTable. PdfImportedObjectTable importedObjectTable = Owner.FormTable.GetImportedObjectTable(externalPage); importedObjectTable.Add(externalPage.ObjectID, page.Reference); PagesArray.Elements.Insert(index, page.Reference); Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); PagesArray.Elements.Insert(index, page.Reference); Elements.SetInteger(PdfPages.Keys.Count, PagesArray.Elements.Count); // Import AcroFields, after the external Page has been imported and we have a valid ObjectID for the imported Page ImportAcroFields(page, externalPage); PdfAnnotations.FixImportedAnnotation(page); #endif // @PDF/UA: Page was imported. if (_document._uaManager != null) { _document.Events.OnPageAdded(_document, new PageEventArgs { Page = page, PageIndex = index, EventType = PageEventType.Imported }); } } if (Owner.Settings.TrimMargins.AreSet) { page.TrimMargins = Owner.Settings.TrimMargins; } return(page); }