/// <summary> /// Sets the color to the specified key. /// </summary> /// <param name="elements">The elements.</param> /// <param name="key">The key.</param> /// <param name="color">The color.</param> public static void SetColor(this PdfDictionary.DictionaryElements elements, string key, XColor color) { if (elements == null) { throw new ArgumentNullException("elements"); } if (!string.IsNullOrEmpty(key)) { var arr = new PdfArray(); arr.Elements.Add(new PdfReal(color.R / (double)byte.MaxValue)); arr.Elements.Add(new PdfReal(color.G / (double)byte.MaxValue)); arr.Elements.Add(new PdfReal(color.B / (double)byte.MaxValue)); elements[key] = arr; } }
internal PdfContents(PdfArray array) : base(array) { int count = Elements.Count; for (int idx = 0; idx < count; idx++) { // Convert the references from PdfDictionary to PdfContent PdfItem item = Elements[idx]; PdfReference iref = item as PdfReference; if (iref != null && iref.Value is PdfDictionary) { // The following line is correct! new PdfContent((PdfDictionary)iref.Value); } else throw new InvalidOperationException("Unexpected item in a content stream array."); } }
/// <summary> /// Replaces the page tree by a flat array of indirect references to the pages objects. /// </summary> internal void FlattenPageTree() { // Acrobat creates a balanced tree if the number of pages is rougly more than ten. This is // not difficult but obviously also not necessary. I created a document with 50000 pages with // PDF4NET and Acrobat opened it in less than 2 seconds. //PdfReference xrefRoot = this.Document.Catalog.Elements[PdfCatalog.Keys.Pages] as PdfReference; //PdfDictionary[] pages = GetKids(xrefRoot, null); // Promote inheritable values down the page tree PdfPage.InheritedValues values = new PdfPage.InheritedValues(); PdfPage.InheritValues(this, ref values); PdfDictionary[] pages = GetKids(Reference, values, null); // Replace /Pages in catalog by this object // xrefRoot.Value = this; PdfArray array = new PdfArray(Owner); foreach (PdfDictionary page in pages) { // Fix the parent page.Elements[PdfPage.Keys.Parent] = Reference; array.Elements.Add(page.Reference); } Elements.SetName(Keys.Type, "/Pages"); #if true // direct array Elements.SetValue(Keys.Kids, array); #else // incdirect array this.Document.xrefTable.Add(array); Elements.SetValue(Keys.Kids, array.XRef); #endif Elements.SetInteger(Keys.Count, array.Elements.Count); }
private static Dictionary <string, string> GetFieldsFromPDF(PdfDocument FormDocument) { Dictionary <string, string> dictPDFFields = new Dictionary <string, string>(); if (FormDocument == null || FormDocument.AcroForm == null) { throw new Exception("No PDF with fillable form submitted"); } PdfAcroForm af = FormDocument.AcroForm; foreach (string key in af.Fields.Names) { try { var field = af.Fields[key]; if (field is PdfTextField) { dictPDFFields.Add(key, ((PdfTextField)field).Text); } else if (field is PdfCheckBoxField) { dictPDFFields.Add(key, ((PdfCheckBoxField)field).Checked.ToString()); } else if (field is PdfSignatureField) { dictPDFFields.Add(key, ""); //Leave empty since we just do image filling } else if (field is PdfComboBoxField) { if (((PdfComboBoxField)field).Value is PdfString) { dictPDFFields.Add(key, (((PdfComboBoxField)field).Value as PdfString).Value); } else { dictPDFFields.Add(key, ((PdfComboBoxField)field).Value?.ToString()); } } else if (field is PdfRadioButtonField) { dictPDFFields.Add(key, ((PdfRadioButtonField)field).Value?.ToString()); } else if (field is PdfListBoxField) { PdfListBoxField pl = (PdfListBoxField)field; string values = ""; if (pl.Value is PdfArray) { PdfSharp.Pdf.PdfArray pa = (PdfSharp.Pdf.PdfArray)pl.Value; foreach (PdfString pi in pa.Elements.Items) { if (values.Length > 0) { values += ","; } values += pi.Value; } } else { values = pl.Value.ToString(); } dictPDFFields.Add(key, values); } else { dictPDFFields.Add(key, "Unsupported Type"); } } catch (Exception e) { throw new Exception("Scan of Field '" + key + " failed. " + e.Message); } } return(dictPDFFields); }
/// <summary> /// Encrypts an array. /// </summary> void EncryptArray(PdfArray array) { int count = array.Elements.Count; for (int idx = 0; idx < count; idx++) { PdfItem item = array.Elements[idx]; PdfString value1; PdfDictionary value2; PdfArray value3; if ((value1 = item as PdfString) != null) EncryptString(value1); else if ((value2 = item as PdfDictionary) != null) EncryptDictionary(value2); else if ((value3 = item as PdfArray) != null) EncryptArray(value3); } }
/// <summary> /// Initializes a new instance from an existing dictionary. Used for object type transformation. /// </summary> /// <param name="array">The array.</param> protected PdfArray(PdfArray array) : base(array) { if (array.elements != null) array.elements.SetOwner(this); }
/// <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) { // @PDF/UA 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[PdfPage.Keys.Annots] = annotations; } } } // @PDF/UA: Pages were imported. if (_document._uaManager != null) { _document.Events.OnPageAdded(_document, new PageEventArgs { EventType = PageEventType.Imported }); } }
PdfArray CreateArray(Type type, PdfArray oldArray) { ConstructorInfo ctorInfo; PdfArray array; if (oldArray == null) { // Use contstructor with signature 'Ctor(PdfDocument owner)'. ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(PdfDocument) }, null); Debug.Assert(ctorInfo != null, "No appropriate constructor found for type: " + type.Name); array = ctorInfo.Invoke(new object[] { this.owner.Owner }) as PdfArray; } else { // Use contstructor with signature 'Ctor(PdfDictionary dict)'. ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(PdfArray) }, null); Debug.Assert(ctorInfo != null, "No appropriate constructor found for type: " + type.Name); array = ctorInfo.Invoke(new object[] { oldArray }) as PdfArray; } return array; }
public PdfArray ReadArray(PdfArray array, bool includeReferences) { Debug.Assert(Symbol == Symbol.BeginArray); if (array == null) array = new PdfArray(this.document); int sp = this.stack.SP; ParseObject(Symbol.EndArray); int count = this.stack.SP - sp; PdfItem[] items = this.stack.ToArray(sp, count); this.stack.Reduce(count); for (int idx = 0; idx < count; idx++) { PdfItem val = items[idx]; if (includeReferences && val is PdfReference) val = ReadReference((PdfReference)val, includeReferences); array.Elements.Add(val); } return array; }
// Write labels to the PDF internal void WriteLabels () { if (!edited) { return; } // Grab the labels element, creating it if necessary PdfDictionary labels_dict; if (!pdf_elements.ContainsKey (name_labels)) { labels_dict = new PdfDictionary (pdf_document); pdf_elements.Add (name_labels, labels_dict); } else { labels_dict = pdf_elements.GetDictionary (name_labels); } labels_dict.Elements.Clear (); // Create the number tree PdfArray number_tree = new PdfArray (pdf_document); // Add the range-start, attrib-dict pairs foreach (int range_start in page_labels.Keys) { number_tree.Elements.Add (new PdfInteger (range_start)); PageLabelFormat label_format = page_labels[range_start]; PdfDictionary r_attribs = new PdfDictionary (pdf_document); if (label_format.number_style.Length > 0) { r_attribs.Elements.Add (name_fmt, new PdfName (label_format.number_style)); } if (label_format.first_number > 1) { r_attribs.Elements.Add (name_start_at, new PdfInteger (label_format.first_number)); } if (label_format.prefix.Length > 0) { r_attribs.Elements.Add (name_prefix, new PdfString (label_format.prefix)); } number_tree.Elements.Add (r_attribs); } labels_dict.Elements.Add (name_numtree, number_tree); }
static void Main(string[] args) { // Get a fresh copy of the sample PDF file string filename = "Portable Document Format.pdf"; File.Copy(Path.Combine("../../../../../PDFs/", filename), Path.Combine(Directory.GetCurrentDirectory(), filename), true); // Read document into memory for modification PdfDocument document = PdfReader.Open(filename); // The current version of PDFsharp doesn't support the concept of // 'actions'. Actions will come in a future version, but if you need them // now, you can have them 'handmade'. // // This sample works on PDF objects directly, therefore some knowledge of // the structure of PDF is required. // If you are not familiar with the portable document format, first read // at least chapter 3 in Adobe's PDF Reference // (http://partners.adobe.com/public/developer/pdf/index_reference.html). // If you can read German, I recommend chapter 12 of 'Die PostScript & // PDF-Bibel', a much more interesting reading than the bone-dry Adobe // books (http://www.pdflib.com/de/produkte/mehr/bibel/index.html). // // The sample task is to add an 'open action' to the document so that it // starts with the content of page 3 magnified just enough to fit the // height of the page within the window. // First we have to create a new dictionary that defines the action. PdfDictionary dict = new PdfDictionary(document); // According to the PDF Reference the dictionary requires two elements. // A key /S that specifies the 'GoTo' action, // and a key /D that describes the destination. // Adding a name as value of key /S is easy. dict.Elements["/S"] = new PdfName("/GoTo"); // The destination is described by an array. PdfArray array = new PdfArray(document); // Set the array as the value of key /D. // This makes the array a direct object of the dictionary. dict.Elements["/D"] = array; // Now add the elements to the array. According to the PDF Reference it // must be three for a page as the target of a 'GoTo' action. // The first element is an indirect reference to the destination page. // To add an indirect reference to the page three, we first need the // PdfReference object of that page. // (The index in the Pages collection is zero based, therefore Pages[2]) PdfReference iref = PdfInternals.GetReference(document.Pages[2]); // Add the reference to the third page as the first array element. // Adding the iref (instead of the PdfPage object itself) makes it an // indirect reference. array.Elements.Add(iref); // The second element is the name /FitV to indicate 'fit vertically'. array.Elements.Add(new PdfName("/FitV")); // /FitV requires the horizontal coordinate that will be positioned at the // left edge of the window. We set -32768 because Acrobat uses this value // to show the full page (it means 'left aligned' anyway if the window is // so small that a horizontal scroll bar is required). array.Elements.Add(new PdfInteger(-32768)); // Now that the action dictionary is complete, we can add it to the // document's object table. // Adding an object to the object table makes it an indirect object. document.Internals.AddObject(dict); // Finally we must add the action dictionary to the /OpenAction key of // the document's catalog as an indirect value. document.Internals.Catalog.Elements["/OpenAction"] = PdfInternals.GetReference(dict); // Using PDFsharp we never deal with object numbers. We simply put the // objects together and the PDFsharp framework does the rest. // Save the document... document.Save(filename); // ...and start a viewer. Process.Start(filename); }
PdfDictionary BuildShadingFunction3(GradientStopCollection gradients, bool softMask, PdfColorMode colorMode) { int count = gradients.Count; Debug.Assert(count >= 2); // // Build a Type 3 function with an array of n-1 Type 2 functions PdfDictionary fn1 = new PdfDictionary(); fn1.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function fn1.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn1.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray = new PdfArray(); fn1.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append("0 1"); } bounds.Append(']'); encode.Append(']'); fn1.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); fn1.Elements["/Encode"] = new PdfLiteral(encode.ToString()); return fn1; }
/// <summary> /// Builds the shading function of the specified gradient stop collection. /// </summary> protected PdfDictionary BuildShadingFunction(GradientStopCollection gradients, bool softMask, PdfColorMode colorMode, bool reverse, out PdfDictionary funcReverse) { PdfDictionary func = new PdfDictionary(); int count = gradients.Count; Debug.Assert(count >= 2); if (CanOptimizeForTwoColors(gradients)) { funcReverse = null; // Build a Type 3 function with an array of 2 Type 2 functions func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); PdfArray fnarray = new PdfArray(); func.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append(reverse ? "1 0" : "0 1"); } bounds.Append(']'); encode.Append(']'); func.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); func.Elements["/Encode"] = new PdfLiteral(encode.ToString()); } else { #if true funcReverse = BuildShadingFunction3(gradients, softMask, colorMode); Context.PdfDocument.Internals.AddObject(funcReverse); func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/Encode"] = new PdfLiteral("[1 0]"); func.Elements["/Bounds"] = new PdfLiteral("[]"); func.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray0 = new PdfArray(); fnarray0.Elements.Add(funcReverse); func.Elements["/Functions"] = fnarray0; #else // // Build a Type 3 function with an array of n-1 Type 2 functions PdfDictionary fn1 = new PdfDictionary(); func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/Encode"] = new PdfLiteral("[1 0]"); func.Elements["/Bounds"] = new PdfLiteral("[]"); func.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray0 = new PdfArray(); fnarray0.Elements.Add(fn1); func.Elements["/Functions"] = fnarray0; fn1.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function fn1.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn1.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); PdfArray fnarray = new PdfArray(); fn1.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0.ScA) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1.ScA) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1]"); } else { fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Range"] = new PdfLiteral("[0 1 0 1 0 1]"); } fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); //this.renderer.Owner.Internals.AddObject(fn2); //fnarray.Elements.Add(fn2.Reference); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append("0 1"); } bounds.Append(']'); encode.Append(']'); fn1.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); fn1.Elements["/Encode"] = new PdfLiteral(encode.ToString()); #endif } return func; }
void SplitDestinationPage(PdfArray destination) // Reference: 8.2 Destination syntax / Page 582 { // ReSharper disable HeuristicUnreachableCode //#pragma warning disable 162 // The destination page may not yet have been transformed to PdfPage. PdfDictionary destPage = (PdfDictionary)((PdfReference)destination.Elements[0]).Value; PdfPage page = destPage as PdfPage; if (page == null) { page = new PdfPage(destPage); } DestinationPage = page; PdfName type = destination.Elements[1] as PdfName; if (type != null) { PageDestinationType = (PdfPageDestinationType)Enum.Parse(typeof(PdfPageDestinationType), type.Value.Substring(1), true); switch (PageDestinationType) { // [page /XYZ left top zoom] -- left, top, and zoom can be null. case PdfPageDestinationType.Xyz: Left = destination.Elements.GetNullableReal(2); Top = destination.Elements.GetNullableReal(3); Zoom = destination.Elements.GetNullableReal(4); // For this parameter, null and 0 have the same meaning. break; // [page /Fit] case PdfPageDestinationType.Fit: // /Fit has no parameters. break; // [page /FitH top] -- top can be null. case PdfPageDestinationType.FitH: Top = destination.Elements.GetNullableReal(2); break; // [page /FitV left] -- left can be null. case PdfPageDestinationType.FitV: Left = destination.Elements.GetNullableReal(2); break; // [page /FitR left bottom right top] -- left, bottom, right, and top must not be null. // TODO An exception in GetReal leads to an inconsistent document. Deal with that - e.g. by registering the corruption and preventing the user from saving the corrupted document. case PdfPageDestinationType.FitR: Left = destination.Elements.GetReal(2); Bottom = destination.Elements.GetReal(3); Right = destination.Elements.GetReal(4); Top = destination.Elements.GetReal(5); break; // [page /FitB] case PdfPageDestinationType.FitB: // /Fit has no parameters. break; // [page /FitBH top] -- top can be null. case PdfPageDestinationType.FitBH: Top = destination.Elements.GetReal(2); break; // [page /FitBV left] -- left can be null. case PdfPageDestinationType.FitBV: Left = destination.Elements.GetReal(2); break; default: throw new ArgumentOutOfRangeException(); } } //#pragma warning restore 162 // ReSharper restore HeuristicUnreachableCode }
/// <summary> /// Initializes this instance from an existing 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."); PdfArray destArray = null; if (dest != null) { destArray = dest as PdfArray; if (destArray != null) { 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]; destArray = dest as PdfArray; if (destArray != null) { // Replace Action with /Dest entry. Elements.Remove(Keys.A); Elements.Add(Keys.Dest, destArray); SplitDestinationPage(destArray); } 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(); }
internal ArrayElements(PdfArray array) { _elements = new List <PdfItem>(); _ownerArray = array; }
/// <summary> /// Reads PDF object from input stream. /// </summary> /// <param name="pdfObject">Either the instance of a derived type or null. If it is null /// an appropriate object is created.</param> /// <param name="objectID">The address of the object.</param> /// <param name="includeReferences">If true, specifies that all indirect objects /// are included recursively.</param> public PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID, bool includeReferences) { MoveToObject(objectID); int objectNumber = ReadInteger(); int generationNumber = ReadInteger(); #if DEBUG // The following assertion sometime failed (see below) //Debug.Assert(objectID == new PdfObjectID(objectNumber, generationNumber)); if (objectID != new PdfObjectID(objectNumber, generationNumber)) { // A special kind of bug? Or is this an undocumented PDF feature? // PDF4NET 2.6 provides a sample called 'Unicode', which produces a file 'unicode.pdf' // The iref table of this file contains the following entries: // iref // 0 148 // 0000000000 65535 f // 0000000015 00000 n // 0000000346 00000 n // .... // 0000083236 00000 n // 0000083045 00000 n // 0000083045 00000 n // 0000083045 00000 n // 0000083045 00000 n // 0000080334 00000 n // .... // Object 84, 85, 86, and 87 maps to the same dictionary, but all PDF readers I tested // ignores this mismatch! The following assertion failed about 50 times with this file. #if true_ string message = String.Format("xref entry {0} {1} maps to object {2} {3}.", objectID.ObjectNumber, objectID.GenerationNumber, objectNumber, generationNumber); Debug.Assert(false, message); #endif } #endif // Always use object ID from iref table (see above) objectNumber = objectID.ObjectNumber; generationNumber = objectID.GenerationNumber; #if true_ Debug.WriteLine(String.Format("obj: {0} {1}", objectNumber, generationNumber)); #endif ReadSymbol(Symbol.Obj); bool checkForStream = false; Symbol symbol = ScanNextToken(); switch (symbol) { case Symbol.BeginArray: PdfArray array; if (pdfObject == null) array = new PdfArray(this.document); else array = (PdfArray)pdfObject; //PdfObject.RegisterObject(array, objectID, generation); pdfObject = ReadArray(array, includeReferences); pdfObject.SetObjectID(objectNumber, generationNumber); break; case Symbol.BeginDictionary: PdfDictionary dict; if (pdfObject == null) dict = new PdfDictionary(this.document); else dict = (PdfDictionary)pdfObject; //PdfObject.RegisterObject(dict, objectID, generation); checkForStream = true; pdfObject = ReadDictionary(dict, includeReferences); pdfObject.SetObjectID(objectNumber, generationNumber); break; // Acrobat 6 Professional proudly presents: The Null object! // Even with a one-digit object number an indirect reference «x 0 R» to this object is // one character larger than the direct use of «null». Probable this is the reason why // it is true that Acrobat Web Capture 6.0 creates this object, but obviously never // creates a reference to it! case Symbol.Null: pdfObject = new PdfNullObject(this.document); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Boolean: pdfObject = new PdfBooleanObject(this.document, this.lexer.Token == Boolean.TrueString); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Integer: pdfObject = new PdfIntegerObject(this.document, this.lexer.TokenToInteger); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.UInteger: pdfObject = new PdfUIntegerObject(this.document, this.lexer.TokenToUInteger); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Real: pdfObject = new PdfRealObject(this.document, this.lexer.TokenToReal); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.String: pdfObject = new PdfStringObject(this.document, this.lexer.Token); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Name: pdfObject = new PdfNameObject(this.document, this.lexer.Token); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Keyword: // Should not come here anymore throw new NotImplementedException("Keyword"); default: // Should not come here anymore throw new NotImplementedException("unknown token"); } symbol = ScanNextToken(); if (symbol == Symbol.BeginStream) { PdfDictionary dict = (PdfDictionary)pdfObject; Debug.Assert(checkForStream, "Unexpected stream..."); int length = GetStreamLength(dict); byte[] bytes = this.lexer.ReadStream(length); #if true_ if (dict.Elements.GetString("/Filter") == "/FlateDecode") { if (dict.Elements["/Subtype"] == null) { try { byte[] decoded = Filtering.FlateDecode.Decode(bytes); if (decoded.Length == 0) goto End; string pageContent = Filtering.FlateDecode.DecodeToString(bytes); if (pageContent.Length > 100) pageContent = pageContent.Substring(pageContent.Length - 100); pageContent.GetType(); bytes = decoded; dict.Elements.Remove("/Filter"); dict.Elements.SetInteger("/Length", bytes.Length); } catch { } } End:; } #endif PdfDictionary.PdfStream stream = new PdfDictionary.PdfStream(bytes, dict); dict.Stream = stream; ReadSymbol(Symbol.EndStream); symbol = ScanNextToken(); } if (symbol != Symbol.EndObj) throw new PdfReaderException(PSSR.UnexpectedToken(this.lexer.Token)); return pdfObject; }
//void RealizeImageBrush(ImageBrush brush, XForm xform) //{ //} //void RealizeVisualBrush(VisualBrush brush, XForm xform) //{ //} /// <summary> /// Builds the shading function of the specified gradient stop collection. /// </summary> PdfDictionary BuildShadingFunction(GradientStopCollection gradients, PdfColorMode colorMode) { bool softMask = this.writer.renderMode == RenderMode.SoftMask; PdfDictionary func = new PdfDictionary(); int count = gradients.Count; Debug.Assert(count >= 2); if (count == 2) { // Build one Type 2 function func.Elements["/FunctionType"] = new PdfInteger(2); // Type 2 - Exponential Interpolation Function Color clr0 = gradients[0].Color; Color clr1 = gradients[1].Color; if (softMask) { clr0 = Utils.AlphaToGray(clr0); clr1 = Utils.AlphaToGray(clr1); } func.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); func.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); func.Elements["/Domain"] = new PdfLiteral("[0 1]"); func.Elements["/N"] = new PdfInteger(1); // be linear } else { // Build a Type 3 function with an array of n-1 Type 2 functions func.Elements["/FunctionType"] = new PdfInteger(3); // Type 3 - Stitching Function func.Elements["/Domain"] = new PdfLiteral("[0 1]"); PdfArray fnarray = new PdfArray(); func.Elements["/Functions"] = fnarray; StringBuilder bounds = new StringBuilder("["); StringBuilder encode = new StringBuilder("["); for (int idx = 1; idx < count; idx++) { PdfDictionary fn2 = new PdfDictionary(); fn2.Elements["/FunctionType"] = new PdfInteger(2); Color clr0 = gradients[idx - 1].Color; Color clr1 = gradients[idx].Color; if (softMask) { clr0 = Utils.AlphaToGray(clr0); clr1 = Utils.AlphaToGray(clr1); } fn2.Elements["/C0"] = new PdfLiteral("[" + PdfEncoders.ToString(clr0, colorMode) + "]"); fn2.Elements["/C1"] = new PdfLiteral("[" + PdfEncoders.ToString(clr1, colorMode) + "]"); fn2.Elements["/Domain"] = new PdfLiteral("[0 1]"); fn2.Elements["/N"] = new PdfInteger(1); //this.renderer.Owner.Internals.AddObject(fn2); //fnarray.Elements.Add(fn2.Reference); fnarray.Elements.Add(fn2); if (idx > 1) { bounds.Append(' '); encode.Append(' '); } if (idx < count - 1) bounds.Append(PdfEncoders.ToString(gradients[idx].Offset)); encode.Append("0 1"); } bounds.Append(']'); //encode.Append(" 0 1"); encode.Append(']'); func.Elements["/Bounds"] = new PdfLiteral(bounds.ToString()); func.Elements["/Encode"] = new PdfLiteral(encode.ToString()); } return func; }
/// <summary> /// Parses whatever comes until the specified stop symbol is reached. /// </summary> void ParseObject(Symbol stop) { #if DEBUG_ ParseObjectCounter++; Debug.WriteLine(ParseObjectCounter.ToString()); if (ParseObjectCounter == 178) GetType(); #endif Symbol symbol; while ((symbol = ScanNextToken()) != Symbol.Eof) { if (symbol == stop) return; switch (symbol) { case Symbol.Comment: // ignore comments break; case Symbol.Null: this.stack.Shift(PdfNull.Value); break; case Symbol.Boolean: this.stack.Shift(new PdfBoolean(this.lexer.TokenToBoolean)); break; case Symbol.Integer: this.stack.Shift(new PdfInteger(this.lexer.TokenToInteger)); break; case Symbol.UInteger: this.stack.Shift(new PdfUInteger(this.lexer.TokenToUInteger)); break; case Symbol.Real: this.stack.Shift(new PdfReal(this.lexer.TokenToReal)); break; case Symbol.String: //this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.PDFDocEncoding)); this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.RawEncoding)); break; case Symbol.UnicodeString: this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.Unicode)); break; case Symbol.HexString: this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.HexLiteral)); break; case Symbol.UnicodeHexString: this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.Unicode | PdfStringFlags.HexLiteral)); break; case Symbol.Name: this.stack.Shift(new PdfName(this.lexer.Token)); break; case Symbol.R: { Debug.Assert(this.stack.GetItem(-1) is PdfInteger && this.stack.GetItem(-2) is PdfInteger); PdfObjectID objectID = new PdfObjectID(this.stack.GetInteger(-2), this.stack.GetInteger(-1)); PdfReference iref = this.document.irefTable[objectID]; if (iref == null) { // If a document has more than one PdfXRefTable it is possible that the first trailer has // indirect references to objects whos iref entry is not yet read in. if (this.document.irefTable.IsUnderConstruction) { // XRefTable not complete when trailer is read. Create temporary irefs that are // removed later in PdfTrailer.FixXRefs. iref = new PdfReference(objectID, 0); this.stack.Reduce(iref, 2); break; } // PDF Reference section 3.2.9: // An indirect reference to an undefined object is not an error; // it is simply treated as a reference to the null object. this.stack.Reduce(PdfNull.Value, 2); // Let's see what null objects are good for... //Debug.Assert(false, "Null object detected!"); //this.stack.Reduce(PdfNull.Value, 2); } else this.stack.Reduce(iref, 2); break; } case Symbol.BeginArray: PdfArray array = new PdfArray(this.document); ReadArray(array, false); this.stack.Shift(array); break; case Symbol.BeginDictionary: PdfDictionary dict = new PdfDictionary(this.document); ReadDictionary(dict, false); this.stack.Shift(dict); break; case Symbol.BeginStream: throw new NotImplementedException(); default: string error = this.lexer.Token; Debug.Assert(false, "Unexpected: " + error); break; } } throw new PdfReaderException("Unexpected end of file."); }
internal ArrayElements(PdfArray array) { this.elements = new ArrayList(); this.owner = array; }
/// <summary> /// Retrieves the raw data for the colorspace. /// </summary> /// <returns>The raw data from the PdfArray of PdfReference.</returns> protected virtual IEnumerable<byte> GetRawPalette(PdfArray array) { if (array == null) throw new ArgumentNullException("array", "The indexed color array was null."); foreach(var item in array.Elements) { var number = (item as PdfInteger); if (number == null) yield return(0); yield return (Convert.ToByte(number.Value)); } }
/// <summary> /// Moves this instance to another dictionary during object type transformation. /// </summary> internal void SetOwner(PdfArray array) { this.owner = array; array.elements = this; }