///// <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 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> /// 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); // @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); }