/// <summary> /// Maps the specified external object to the substitute object in this document. /// Returns null if no such object exists. /// </summary> public PdfObject MapExternalObject(PdfObject externalObject) { PdfFormXObjectTable table = _document.FormTable; PdfImportedObjectTable iot = table.GetImportedObjectTable(externalObject.Owner); PdfReference reference = iot[externalObject.ObjectID]; return reference == null ? null : reference.Value; }
public void DetachDocument(PdfDocument.DocumentHandle handle) { if (handle.IsAlive) { foreach (Selector selector in _forms.Keys) { PdfImportedObjectTable table = _forms[selector]; if (table.ExternalDocument != null && table.ExternalDocument.Handle == handle) { _forms.Remove(selector); break; } } } // Clean table bool itemRemoved = true; while (itemRemoved) { itemRemoved = false; foreach (Selector selector in _forms.Keys) { PdfImportedObjectTable table = _forms[selector]; if (table.ExternalDocument == null) { _forms.Remove(selector); itemRemoved = true; break; } } } }
/// <summary> /// Gets the imported object table. /// </summary> public PdfImportedObjectTable GetImportedObjectTable(PdfPage page) { // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(page); PdfImportedObjectTable importedObjectTable; if (!_forms.TryGetValue(selector, out importedObjectTable)) { importedObjectTable = new PdfImportedObjectTable(Owner, page.Owner); _forms[selector] = importedObjectTable; } return(importedObjectTable); }
/// <summary> /// Gets a PdfFormXObject from an XPdfForm. Because the returned objects must be unique, always /// a new instance of PdfFormXObject is created if none exists for the specified form. /// </summary> public PdfFormXObject GetForm(XForm form) { // If the form already has a PdfFormXObject, return it. if (form._pdfForm != null) { Debug.Assert(form.IsTemplate, "An XPdfForm must not have a PdfFormXObject."); if (ReferenceEquals(form._pdfForm.Owner, Owner)) { return(form._pdfForm); } //throw new InvalidOperationException("Because of a current limitation of PDFsharp an XPdfForm object can be used only within one single PdfDocument."); // Dispose PdfFromXObject when document has changed form._pdfForm = null; } XPdfForm pdfForm = form as XPdfForm; if (pdfForm != null) { // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(form); PdfImportedObjectTable importedObjectTable; if (!_forms.TryGetValue(selector, out importedObjectTable)) { // No: Get the external document from the form and create ImportedObjectTable. PdfDocument doc = pdfForm.ExternalDocument; importedObjectTable = new PdfImportedObjectTable(Owner, doc); _forms[selector] = importedObjectTable; } PdfFormXObject xObject = importedObjectTable.GetXObject(pdfForm.PageNumber); if (xObject == null) { xObject = new PdfFormXObject(Owner, importedObjectTable, pdfForm); importedObjectTable.SetXObject(pdfForm.PageNumber, xObject); } return(xObject); } Debug.Assert(form.GetType() == typeof(XForm)); form._pdfForm = new PdfFormXObject(Owner, form); return(form._pdfForm); }
/// <summary> /// Gets the imported object table. /// </summary> public PdfImportedObjectTable GetImportedObjectTable(PdfDocument document) { if (document == null) { throw new ArgumentNullException("document"); } // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(document); PdfImportedObjectTable importedObjectTable; if (!_forms.TryGetValue(selector, out importedObjectTable)) { // Create new table for document. importedObjectTable = new PdfImportedObjectTable(Owner, document); _forms[selector] = importedObjectTable; } return(importedObjectTable); }
/// <summary> /// Gets a PdfFormXObject from an XPdfForm. Because the returned objects must be unique, always /// a new instance of PdfFormXObject is created if none exists for the specified form. /// </summary> public PdfFormXObject GetForm(XForm form) { // If the form already has a PdfFormXObject, return it. if (form._pdfForm != null) { Debug.Assert(form.IsTemplate, "An XPdfForm must not have a PdfFormXObject."); if (ReferenceEquals(form._pdfForm.Owner, Owner)) return form._pdfForm; //throw new InvalidOperationException("Because of a current limitation of PDFsharp an XPdfForm object can be used only within one single PdfDocument."); // Dispose PdfFromXObject when document has changed form._pdfForm = null; } XPdfForm pdfForm = form as XPdfForm; if (pdfForm != null) { // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(form); PdfImportedObjectTable importedObjectTable; if (!_forms.TryGetValue(selector, out importedObjectTable)) { // No: Get the external document from the form and create ImportedObjectTable. PdfDocument doc = pdfForm.ExternalDocument; importedObjectTable = new PdfImportedObjectTable(Owner, doc); _forms[selector] = importedObjectTable; } PdfFormXObject xObject = importedObjectTable.GetXObject(pdfForm.PageNumber); if (xObject == null) { xObject = new PdfFormXObject(Owner, importedObjectTable, pdfForm); importedObjectTable.SetXObject(pdfForm.PageNumber, xObject); } return xObject; } Debug.Assert(form.GetType() == typeof(XForm)); form._pdfForm = new PdfFormXObject(Owner, form); return form._pdfForm; }
internal PdfFormXObject(PdfDocument thisDocument, PdfImportedObjectTable importedObjectTable, XPdfForm form) : base(thisDocument) { Debug.Assert(ReferenceEquals(thisDocument, importedObjectTable.Owner)); Elements.SetName(Keys.Type, "/XObject"); Elements.SetName(Keys.Subtype, "/Form"); if (form.IsTemplate) { Debug.Assert(importedObjectTable == null); // TODO more initialization here??? return; } Debug.Assert(importedObjectTable != null); XPdfForm pdfForm = form; // Get import page PdfPages importPages = importedObjectTable.ExternalDocument.Pages; if (pdfForm.PageNumber < 1 || pdfForm.PageNumber > importPages.Count) { PSSR.ImportPageNumberOutOfRange(pdfForm.PageNumber, importPages.Count, form._path); } PdfPage importPage = importPages[pdfForm.PageNumber - 1]; // Import resources PdfItem res = importPage.Elements["/Resources"]; if (res != null) // unlikely but possible { #if true // Get root object PdfObject root; if (res is PdfReference) { root = ((PdfReference)res).Value; } else { root = (PdfDictionary)res; } root = ImportClosure(importedObjectTable, thisDocument, root); // If the root was a direct object, make it indirect. if (root.Reference == null) { thisDocument._irefTable.Add(root); } Debug.Assert(root.Reference != null); Elements["/Resources"] = root.Reference; #else // Get transitive closure PdfObject[] resources = importPage.Owner.Internals.GetClosure(resourcesRoot); int count = resources.Length; #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(resources[idx].XRef != null); Debug.Assert(resources[idx].XRef.Document != null); Debug.Assert(resources[idx].Document != null); if (resources[idx].ObjectID.ObjectNumber == 12) { GetType(); } } #endif // 1st step. Already imported objects are reused and new ones are cloned. for (int idx = 0; idx < count; idx++) { PdfObject obj = resources[idx]; if (importedObjectTable.Contains(obj.ObjectID)) { // 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 clone counterpart resources[idx] = iref.Value; } else { // External object was not imported ealier and must be cloned PdfObject clone = obj.Clone(); Debug.Assert(clone.Reference == null); clone.Document = Owner; if (obj.Reference != null) { // add it to this (the importer) document Owner.irefTable.Add(clone); Debug.Assert(clone.Reference != null); // save old object identifier importedObjectTable.Add(obj.ObjectID, clone.Reference); //Debug.WriteLine("Cloned: " + obj.ObjectID.ToString()); } else { // The root object (the /Resources value) is not an indirect object Debug.Assert(idx == 0); // add it to this (the importer) document Owner.irefTable.Add(clone); Debug.Assert(clone.Reference != null); } // replace external object by its clone resources[idx] = clone; } } #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(resources[idx].XRef != null); Debug.Assert(resources[idx].XRef.Document != null); Debug.Assert(resources[idx].Document != null); if (resources[idx].ObjectID.ObjectNumber == 12) { GetType(); } } #endif // 2nd step. Fix up indirect references that still refers to the import document. for (int idx = 0; idx < count; idx++) { PdfObject obj = resources[idx]; Debug.Assert(obj.Owner != null); FixUpObject(importedObjectTable, importedObjectTable.Owner, obj); } // Set resources key to the root of the clones Elements["/Resources"] = resources[0].Reference; #endif } // Take /Rotate into account PdfRectangle rect = importPage.Elements.GetRectangle(PdfPage.Keys.MediaBox); int rotate = importPage.Elements.GetInteger(PdfPage.Keys.Rotate); //rotate = 0; if (rotate == 0) { // Set bounding box to media box Elements["/BBox"] = rect; } else { // TODO: Have to adjust bounding box? (I think not, but I'm not sure -> wait for problem) Elements["/BBox"] = rect; // Rotate the image such that it is upright XMatrix matrix = new XMatrix(); double width = rect.Width; double height = rect.Height; matrix.RotateAtPrepend(-rotate, new XPoint(width / 2, height / 2)); if (rotate != 180) { // Translate the image such that its center lies on the center of the rotated bounding box double offset = (height - width) / 2; if (height > width) { matrix.TranslatePrepend(offset, offset); } else { matrix.TranslatePrepend(-offset, -offset); } } //string item = "[" + PdfEncoders.ToString(matrix) + "]"; //Elements[Keys.Matrix] = new PdfLiteral(item); Elements.SetMatrix(Keys.Matrix, matrix); } // Preserve filter because the content keeps unmodified PdfContent content = importPage.Contents.CreateSingleContent(); #if !DEBUG content.Compressed = true; #endif PdfItem filter = content.Elements["/Filter"]; if (filter != null) { Elements["/Filter"] = filter.Clone(); } // (no cloning needed because the bytes keep untouched) Stream = content.Stream; // new PdfStream(bytes, this); Elements.SetInteger("/Length", content.Stream.Value.Length); }
/// <summary> /// Replace all indirect references to external objects by their cloned counterparts /// owned by the importer document. /// </summary> void FixUpObject_old(PdfImportedObjectTable iot, PdfObject value) { // TODO: merge with PdfXObject.FixUpObject 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 belong to this document? if (iref.Document == Owner) { // Yes: fine 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); dict.Elements[name] = newXRef; } } else if (item is PdfObject) { // Fix up inner objects FixUpObject_old(iot, (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 belongs to this document? if (iref.Document == Owner) { // Yes: fine 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_old(iot, (PdfObject)item); } } } }
/// <summary> /// Gets the imported object table. /// </summary> public PdfImportedObjectTable GetImportedObjectTable(PdfDocument document) { if (document == null) throw new ArgumentNullException("document"); // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(document); PdfImportedObjectTable importedObjectTable; if (!_forms.TryGetValue(selector, out importedObjectTable)) { // Create new table for document. importedObjectTable = new PdfImportedObjectTable(Owner, document); _forms[selector] = importedObjectTable; } return importedObjectTable; }
/// <summary> /// Gets the imported object table. /// </summary> public PdfImportedObjectTable GetImportedObjectTable(PdfPage page) { // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(page); PdfImportedObjectTable importedObjectTable; if (!_forms.TryGetValue(selector, out importedObjectTable)) { importedObjectTable = new PdfImportedObjectTable(Owner, page.Owner); _forms[selector] = importedObjectTable; } return importedObjectTable; }
internal PdfFormXObject(PdfDocument thisDocument, PdfImportedObjectTable importedObjectTable, XPdfForm form) : base(thisDocument) { Debug.Assert(Object.ReferenceEquals(thisDocument, importedObjectTable.Owner)); Elements.SetName(Keys.Type, "/XObject"); Elements.SetName(Keys.Subtype, "/Form"); if (form.IsTemplate) { Debug.Assert(importedObjectTable == null); // TODO more initialization here??? return; } Debug.Assert(importedObjectTable != null); XPdfForm pdfForm = (XPdfForm)form; // Get import page PdfPages importPages = importedObjectTable.ExternalDocument.Pages; if (pdfForm.PageNumber < 1 || pdfForm.PageNumber > importPages.Count) PSSR.ImportPageNumberOutOfRange(pdfForm.PageNumber, importPages.Count, form.path); PdfPage importPage = importPages[pdfForm.PageNumber - 1]; // Import resources PdfItem res = importPage.Elements["/Resources"]; if (res != null) // unlikely but possible { #if true // Get root object PdfObject root; if (res is PdfReference) root = ((PdfReference)res).Value; else root = (PdfDictionary)res; root = ImportClosure(importedObjectTable, thisDocument, root); // If the root was a direct object, make it indirect. if (root.Reference == null) thisDocument.irefTable.Add(root); Debug.Assert(root.Reference != null); Elements["/Resources"] = root.Reference; #else // Get transitive closure PdfObject[] resources = importPage.Owner.Internals.GetClosure(resourcesRoot); int count = resources.Length; #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(resources[idx].XRef != null); Debug.Assert(resources[idx].XRef.Document != null); Debug.Assert(resources[idx].Document != null); if (resources[idx].ObjectID.ObjectNumber == 12) GetType(); } #endif // 1st step. Already imported objects are reused and new ones are cloned. for (int idx = 0; idx < count; idx++) { PdfObject obj = resources[idx]; if (importedObjectTable.Contains(obj.ObjectID)) { // external object was already imported PdfReference iref = importedObjectTable[obj.ObjectID]; Debug.Assert(iref != null); Debug.Assert(iref.Value != null); Debug.Assert(iref.Document == this.Owner); // replace external object by the already clone counterpart resources[idx] = iref.Value; } else { // External object was not imported ealier and must be cloned PdfObject clone = obj.Clone(); Debug.Assert(clone.Reference == null); clone.Document = this.Owner; if (obj.Reference != null) { // add it to this (the importer) document this.Owner.irefTable.Add(clone); Debug.Assert(clone.Reference != null); // save old object identifier importedObjectTable.Add(obj.ObjectID, clone.Reference); //Debug.WriteLine("Cloned: " + obj.ObjectID.ToString()); } else { // The root object (the /Resources value) is not an indirect object Debug.Assert(idx == 0); // add it to this (the importer) document this.Owner.irefTable.Add(clone); Debug.Assert(clone.Reference != null); } // replace external object by its clone resources[idx] = clone; } } #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(resources[idx].XRef != null); Debug.Assert(resources[idx].XRef.Document != null); Debug.Assert(resources[idx].Document != null); if (resources[idx].ObjectID.ObjectNumber == 12) GetType(); } #endif // 2nd step. Fix up indirect references that still refers to the import document. for (int idx = 0; idx < count; idx++) { PdfObject obj = resources[idx]; Debug.Assert(obj.Owner != null); FixUpObject(importedObjectTable, importedObjectTable.Owner, obj); } // Set resources key to the root of the clones Elements["/Resources"] = resources[0].Reference; #endif } // Take /Rotate into account PdfRectangle rect = importPage.Elements.GetRectangle(PdfPage.Keys.MediaBox); int rotate = importPage.Elements.GetInteger(PdfPage.Keys.Rotate); //rotate = 0; if (rotate == 0) { // Set bounding box to media box this.Elements["/BBox"] = rect; } else { // TODO: Have to adjust bounding box? (I think not, but I'm not sure -> wait for problem) this.Elements["/BBox"] = rect; // Rotate the image such that it is upright XMatrix matrix = XMatrix.Identity; double width = rect.Width; double height = rect.Height; matrix.RotateAtPrepend(-rotate, new XPoint(width / 2, height / 2)); // Translate the image such that its center lies on the center of the rotated bounding box double offset = (height - width) / 2; if (height > width) matrix.TranslatePrepend(offset, offset); else matrix.TranslatePrepend(-offset, -offset); //string item = "[" + PdfEncoders.ToString(matrix) + "]"; //Elements[Keys.Matrix] = new PdfLiteral(item); Elements.SetMatrix(Keys.Matrix, matrix); } // Preserve filter because the content keeps unmodified PdfContent content = importPage.Contents.CreateSingleContent(); #if !DEBUG content.Compressed = true; #endif PdfItem filter = content.Elements["/Filter"]; if (filter != null) this.Elements["/Filter"] = filter.Clone(); // (no cloning needed because the bytes keep untouched) this.Stream = content.Stream; // new PdfStream(bytes, this); Elements.SetInteger("/Length", content.Stream.Value.Length); }
/// <summary> /// Replace all indirect references to external objects by their cloned counterparts /// owned by the importer document. /// </summary> void FixUpObject_old(PdfImportedObjectTable iot, PdfObject value) { // TODO: merge with PdfXObject.FixUpObject PdfDictionary dict; PdfArray array; if ((dict = value as PdfDictionary) != null) { // Set document for cloned direct objects if (dict.Owner == null) dict.Document = this.Owner; else Debug.Assert(dict.Owner == this.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 belong to this document? if (iref.Document == this.Owner) { // Yes: fine 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 == this.Owner); dict.Elements[name] = newXRef; } } else if (item is PdfObject) { // Fix up inner objects FixUpObject_old(iot, (PdfObject)item); } } } else if ((array = value as PdfArray) != null) { // Set document for cloned direct objects if (array.Owner == null) array.Document = this.Owner; else Debug.Assert(array.Owner == this.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 belongs to this document? if (iref.Document == this.Owner) { // Yes: fine 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 == this.Owner); array.Elements[idx] = newXRef; } } else if (item is PdfObject) { // Fix up inner objects FixUpObject_old(iot, (PdfObject)item); } } } }
///// <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)) { // 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 { // External object was not imported ealier 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); //// add it to this (the importer) document //owner.irefTable.Add(clone); //Debug.Assert(clone.Reference != null); } // replace external object by its clone elements[idx] = clone; } } #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 (resources[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].XRef != null); Debug.Assert(elements[idx].XRef.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> /// /// </summary> /// <param name="page"></param> /// <returns></returns> public PdfImportedObjectTable GetImportedObjectTable(PdfPage page) { // Is the external PDF file from which is imported already known for the current document? Selector selector = new Selector(page); PdfImportedObjectTable importedObjectTable = this.forms[selector] as PdfImportedObjectTable; if (importedObjectTable == null) { importedObjectTable = new PdfImportedObjectTable(this.owner, page.Owner); this.forms[selector] = importedObjectTable; } return importedObjectTable; }
/// <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."); } }