/// <summary> /// Inherit values from parent node. /// </summary> internal static void InheritValues(PdfDictionary page, InheritedValues values) { // HACK: I'M ABSOLUTELY NOT SURE WHETHER THIS CODE COVERS ALL CASES. if (values.Resources != null) { PdfDictionary resources; PdfItem res = page.Elements[InheritablePageKeys.Resources]; if (res is PdfReference) { resources = (PdfDictionary)((PdfReference)res).Value.Clone(); resources.Document = page.Owner; } else resources = (PdfDictionary)res; if (resources == null) { resources = values.Resources.Clone(); resources.Document = page.Owner; page.Elements.Add(InheritablePageKeys.Resources, resources); } else { foreach (PdfName name in values.Resources.Elements.KeyNames) { if (!resources.Elements.ContainsKey(name.Value)) { PdfItem item = values.Resources.Elements[name]; if (item is PdfObject) item = item.Clone(); resources.Elements.Add(name.ToString(), item); } } } } if (values.MediaBox != null && page.Elements[InheritablePageKeys.MediaBox] == null) page.Elements[InheritablePageKeys.MediaBox] = values.MediaBox; if (values.CropBox != null && page.Elements[InheritablePageKeys.CropBox] == null) page.Elements[InheritablePageKeys.CropBox] = values.CropBox; if (values.Rotate != null && page.Elements[InheritablePageKeys.Rotate] == null) page.Elements[InheritablePageKeys.Rotate] = values.Rotate; }
/// <summary> /// Add all inheritable values from the specified page to the specified values structure. /// </summary> internal static void InheritValues(PdfDictionary page, ref InheritedValues values) { PdfItem item = page.Elements[InheritablePageKeys.Resources]; if (item != null) { PdfReference reference = item as PdfReference; if (reference != null) { values.Resources = (PdfDictionary)(reference.Value); } else { values.Resources = (PdfDictionary)item; } } item = page.Elements[InheritablePageKeys.MediaBox]; if (item != null) { values.MediaBox = new PdfRectangle(item); } item = page.Elements[InheritablePageKeys.CropBox]; if (item != null) { values.CropBox = new PdfRectangle(item); } item = page.Elements[InheritablePageKeys.Rotate]; if (item != null) { if (item is PdfReference) { item = ((PdfReference)item).Value; } values.Rotate = (PdfInteger)item; } }
internal override void WriteObject(PdfWriter writer) { // HACK: temporarily flip media box if Landscape PdfRectangle mediaBox = MediaBox; // TODO: Take /Rotate into account if (_orientation == PageOrientation.Landscape) MediaBox = new PdfRectangle(mediaBox.X1, mediaBox.Y1, mediaBox.Y2, mediaBox.X2); #if true // Add transparency group to prevent rendering problems of Adobe viewer. // Update (PDFsharp 1.50 beta 3): Add transparency group only of ColorMode is defined. // Rgb is the default for the ColorMode, but if user sets it to Undefined then // we respect this and skip the transparency group. TransparencyUsed = true; // TODO: check XObjects if (TransparencyUsed && !Elements.ContainsKey(Keys.Group) && _document.Options.ColorMode != PdfColorMode.Undefined) { PdfDictionary group = new PdfDictionary(); _elements["/Group"] = group; if (_document.Options.ColorMode != PdfColorMode.Cmyk) group.Elements.SetName("/CS", "/DeviceRGB"); else group.Elements.SetName("/CS", "/DeviceCMYK"); group.Elements.SetName("/S", "/Transparency"); //False is default: group.Elements["/I"] = new PdfBoolean(false); //False is default: group.Elements["/K"] = new PdfBoolean(false); } #endif #if DEBUG_ PdfItem item = Elements["/MediaBox"]; if (item != null) item.GetType(); #endif base.WriteObject(writer); if (_orientation == PageOrientation.Landscape) MediaBox = mediaBox; }
/// <summary> /// Initializes a new instance of the PdfRectangle class with the specified PdfArray. /// </summary> internal PdfRectangle(PdfItem item) { if (item == null || item is PdfNull) { return; } if (item is PdfReference) { item = ((PdfReference)item).Value; } PdfArray array = item as PdfArray; if (array == null) { throw new InvalidOperationException(PSSR.UnexpectedTokenInPdfFile); } _x1 = array.Elements.GetReal(0); _y1 = array.Elements.GetReal(1); _x2 = array.Elements.GetReal(2); _y2 = array.Elements.GetReal(3); }
/// <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> /// Initializes this instance from an exisiting PDF document. /// </summary> void Initialize() { string title; if (Elements.TryGetString(Keys.Title, out title)) { Title = title; } PdfReference parentRef = Elements.GetReference(Keys.Parent); if (parentRef != null) { PdfOutline parent = parentRef.Value as PdfOutline; if (parent != null) { Parent = parent; } } Count = Elements.GetInteger(Keys.Count); PdfArray colors = Elements.GetArray(Keys.C); if (colors != null && colors.Elements.Count == 3) { double r = colors.Elements.GetReal(0); double g = colors.Elements.GetReal(1); double b = colors.Elements.GetReal(2); TextColor = XColor.FromArgb((int)(r * 255), (int)(g * 255), (int)(b * 255)); } // Style directly works on dictionary element. PdfItem dest = Elements.GetValue(Keys.Dest); PdfItem a = Elements.GetValue(Keys.A); Debug.Assert(dest == null || a == null, "Either destination or goto action."); if (dest != null) { if (dest is PdfArray destArray) { SplitDestinationPage(destArray); } else { Debug.Assert(false, "See what to do when this happened."); } } else if (a != null) { // The dictionary should be a GoTo action. PdfDictionary action = a as PdfDictionary; if (action != null && action.Elements.GetName(PdfAction.Keys.S) == "/GoTo") { dest = action.Elements[PdfGoToAction.Keys.D]; if (dest is PdfArray destArray) { // Replace Action with /Dest entry. Elements.Remove(Keys.A); Elements.Add(Keys.Dest, destArray); SplitDestinationPage(destArray); } else if (dest is PdfReference detRef) { // Replace Action with /Dest entry. Elements.Remove(Keys.A); Elements.Add(Keys.Dest, detRef.Value); SplitDestinationPage((PdfArray)detRef.Value); } else { throw new Exception("Destination Array expected."); } } else { Debug.Assert(false, "See what to do when this happened."); } } else { // Neither destination page nor GoTo action. } InitializeChildren(); }