using System; using System.IO; using System.Text; using System.Collections; using System.util.collections; using System.util; using iTextSharp.text; using iTextSharp.text.pdf.events; using iTextSharp.text.pdf.interfaces; using iTextSharp.text.pdf.intern; using iTextSharp.text.pdf.collection; using iTextSharp.text.xml.xmp; using Org.BouncyCastle.X509; /* * $Id: PdfWriter.cs,v 1.48 2008/05/13 11:25:23 psoares33 Exp $ * * * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * * The Original Code is 'iText, a free JAVA-PDF library'. * * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. * All Rights Reserved. * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. * * Contributor(s): all the names of the contributors are added in the source code * where applicable. * * Alternatively, the contents of this file may be used under the terms of the * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the * provisions of LGPL are applicable instead of those above. If you wish to * allow use of your version of this file only under the terms of the LGPL * License and not to allow others to use your version of this file under * the MPL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the LGPL. * If you do not delete the provisions above, a recipient may use your version * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. * * This library is free software; you can redistribute it and/or modify it * under the terms of the MPL as stated above or under the terms of the GNU * Library General Public License as published by the Free Software Foundation; * either version 2 of the License, or any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more * details. * * If you didn't download this code from the following link, you should check if * you aren't using an obsolete version: * http://www.lowagie.com/iText/ */ namespace iTextSharp.text.pdf { /** * A DocWriter class for PDF. *

* When this PdfWriter is added * to a certain PdfDocument, the PDF representation of every Element * added to this Document will be written to the outputstream.

*/ public class PdfWriter : DocWriter, IPdfViewerPreferences, IPdfEncryptionSettings, IPdfVersion, IPdfDocumentActions, IPdfPageActions, IPdfXConformance, IPdfRunDirection, IPdfAnnotations { // INNER CLASSES /** * This class generates the structure of a PDF document. *

* This class covers the third section of Chapter 5 in the 'Portable Document Format * Reference Manual version 1.3' (page 55-60). It contains the body of a PDF document * (section 5.14) and it can also generate a Cross-reference Table (section 5.15). * * @see PdfWriter * @see PdfObject * @see PdfIndirectObject */ public class PdfBody { // inner classes /** * PdfCrossReference is an entry in the PDF Cross-Reference table. */ internal class PdfCrossReference : IComparable { // membervariables private int type; /** Byte offset in the PDF file. */ private int offset; private int refnum; /** generation of the object. */ private int generation; // constructors /** * Constructs a cross-reference element for a PdfIndirectObject. * @param refnum * @param offset byte offset of the object * @param generation generationnumber of the object */ internal PdfCrossReference(int refnum, int offset, int generation) { type = 0; this.offset = offset; this.refnum = refnum; this.generation = generation; } /** * Constructs a cross-reference element for a PdfIndirectObject. * @param refnum * @param offset byte offset of the object */ internal PdfCrossReference(int refnum, int offset) { type = 1; this.offset = offset; this.refnum = refnum; this.generation = 0; } internal PdfCrossReference(int type, int refnum, int offset, int generation) { this.type = type; this.offset = offset; this.refnum = refnum; this.generation = generation; } internal int Refnum { get { return refnum; } } /** * Returns the PDF representation of this PdfObject. * @param os * @throws IOException */ public void ToPdf(Stream os) { String s1 = offset.ToString().PadLeft(10, '0'); String s2 = generation.ToString().PadLeft(5, '0'); ByteBuffer buf = new ByteBuffer(40); if (generation == 65535) { buf.Append(s1).Append(' ').Append(s2).Append(" f \n"); } else { buf.Append(s1).Append(' ').Append(s2).Append(" n \n"); } os.Write(buf.Buffer, 0, buf.Size); } /** * Writes PDF syntax to the Stream * @param midSize * @param os * @throws IOException */ public void ToPdf(int midSize, Stream os) { os.WriteByte((byte)type); while (--midSize >= 0) os.WriteByte((byte)((offset >> (8 * midSize)) & 0xff)); os.WriteByte((byte)((generation >> 8) & 0xff)); os.WriteByte((byte)(generation & 0xff)); } /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int CompareTo(Object o) { PdfCrossReference other = (PdfCrossReference)o; return (refnum < other.refnum ? -1 : (refnum==other.refnum ? 0 : 1)); } /** * @see java.lang.Object#equals(java.lang.Object) */ public override bool Equals(Object obj) { if (obj is PdfCrossReference) { PdfCrossReference other = (PdfCrossReference)obj; return (refnum == other.refnum); } else return false; } public override int GetHashCode() { return refnum; } } // membervariables private const int OBJSINSTREAM = 200; /** array containing the cross-reference table of the normal objects. */ private k_Tree xrefs; private int refnum; /** the current byteposition in the body. */ private int position; private PdfWriter writer; private ByteBuffer index; private ByteBuffer streamObjects; private int currentObjNum; private int numObj = 0; // constructors /** * Constructs a new PdfBody. * @param writer */ internal PdfBody(PdfWriter writer) { xrefs = new k_Tree(); xrefs[new PdfCrossReference(0, 0, 65535)] = null; position = writer.Os.Counter; refnum = 1; this.writer = writer; } // methods internal int Refnum { set { this.refnum = value; } } private PdfWriter.PdfBody.PdfCrossReference AddToObjStm(PdfObject obj, int nObj) { if (numObj >= OBJSINSTREAM) FlushObjStm(); if (index == null) { index = new ByteBuffer(); streamObjects = new ByteBuffer(); currentObjNum = IndirectReferenceNumber; numObj = 0; } int p = streamObjects.Size; int idx = numObj++; PdfEncryption enc = writer.crypto; writer.crypto = null; obj.ToPdf(writer, streamObjects); writer.crypto = enc; streamObjects.Append(' '); index.Append(nObj).Append(' ').Append(p).Append(' '); return new PdfWriter.PdfBody.PdfCrossReference(2, nObj, currentObjNum, idx); } internal void FlushObjStm() { if (numObj == 0) return; int first = index.Size; index.Append(streamObjects); PdfStream stream = new PdfStream(index.ToByteArray()); stream.FlateCompress(); stream.Put(PdfName.TYPE, PdfName.OBJSTM); stream.Put(PdfName.N, new PdfNumber(numObj)); stream.Put(PdfName.FIRST, new PdfNumber(first)); Add(stream, currentObjNum); index = null; streamObjects = null; numObj = 0; } /** * Adds a PdfObject to the body. *

* This methods creates a PdfIndirectObject with a * certain number, containing the given PdfObject. * It also adds a PdfCrossReference for this object * to an ArrayList that will be used to build the * Cross-reference Table. * * @param object a PdfObject * @return a PdfIndirectObject * @throws IOException */ internal PdfIndirectObject Add(PdfObject objecta) { return Add(objecta, IndirectReferenceNumber); } internal PdfIndirectObject Add(PdfObject objecta, bool inObjStm) { return Add(objecta, IndirectReferenceNumber, inObjStm); } /** * Gets a PdfIndirectReference for an object that will be created in the future. * @return a PdfIndirectReference */ internal PdfIndirectReference PdfIndirectReference { get { return new PdfIndirectReference(0, IndirectReferenceNumber); } } internal int IndirectReferenceNumber { get { int n = refnum++; xrefs[new PdfCrossReference(n, 0, 65536)] = null; return n; } } /** * Adds a PdfObject to the body given an already existing * PdfIndirectReference. *

* This methods creates a PdfIndirectObject with the number given by * ref, containing the given PdfObject. * It also adds a PdfCrossReference for this object * to an ArrayList that will be used to build the * Cross-reference Table. * * @param object a PdfObject * @param ref a PdfIndirectReference * @return a PdfIndirectObject * @throws IOException */ internal PdfIndirectObject Add(PdfObject objecta, PdfIndirectReference refa) { return Add(objecta, refa.Number); } internal PdfIndirectObject Add(PdfObject objecta, PdfIndirectReference refa, bool inObjStm) { return Add(objecta, refa.Number, inObjStm); } internal PdfIndirectObject Add(PdfObject objecta, int refNumber) { return Add(objecta, refNumber, true); // to false } internal PdfIndirectObject Add(PdfObject objecta, int refNumber, bool inObjStm) { if (inObjStm && objecta.CanBeInObjStm() && writer.FullCompression) { PdfCrossReference pxref = AddToObjStm(objecta, refNumber); PdfIndirectObject indirect = new PdfIndirectObject(refNumber, objecta, writer); xrefs.Remove(pxref); xrefs[pxref] = null; return indirect; } else { PdfIndirectObject indirect = new PdfIndirectObject(refNumber, objecta, writer); PdfCrossReference pxref = new PdfCrossReference(refNumber, position); xrefs.Remove(pxref); xrefs[pxref] = null; indirect.WriteTo(writer.Os); position = writer.Os.Counter; return indirect; } } /** * Returns the offset of the Cross-Reference table. * * @return an offset */ internal int Offset { get { return position; } } /** * Returns the total number of objects contained in the CrossReferenceTable of this Body. * * @return a number of objects */ internal int Size { get { k_Iterator it = xrefs.End.Clone(); it.Prev(); return Math.Max(((PdfCrossReference)((DictionaryEntry)it.Current).Key).Refnum + 1, refnum); } } /** * Returns the CrossReferenceTable of the Body. * @param os * @param root * @param info * @param encryption * @param fileID * @param prevxref * @throws IOException */ internal void WriteCrossReferenceTable(Stream os, PdfIndirectReference root, PdfIndirectReference info, PdfIndirectReference encryption, PdfObject fileID, int prevxref) { int refNumber = 0; if (writer.FullCompression) { FlushObjStm(); refNumber = IndirectReferenceNumber; xrefs[new PdfCrossReference(refNumber, position)] = null; } PdfCrossReference entry = (PdfCrossReference)((DictionaryEntry)xrefs.Begin.Current).Key; int first = entry.Refnum; int len = 0; ArrayList sections = new ArrayList(); for (k_Iterator i = xrefs.Begin.Clone(); i != xrefs.End; i.Next()) { entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; if (first + len == entry.Refnum) ++len; else { sections.Add(first); sections.Add(len); first = entry.Refnum; len = 1; } } sections.Add(first); sections.Add(len); if (writer.FullCompression) { int mid = 4; uint mask = 0xff000000; for (; mid > 1; --mid) { if ((mask & position) != 0) break; mask >>= 8; } ByteBuffer buf = new ByteBuffer(); for (k_Iterator i = xrefs.Begin.Clone(); i != xrefs.End; i.Next()) { entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; entry.ToPdf(mid, buf); } PdfStream xr = new PdfStream(buf.ToByteArray()); buf = null; xr.FlateCompress(); xr.Put(PdfName.SIZE, new PdfNumber(Size)); xr.Put(PdfName.ROOT, root); if (info != null) { xr.Put(PdfName.INFO, info); } if (encryption != null) xr.Put(PdfName.ENCRYPT, encryption); if (fileID != null) xr.Put(PdfName.ID, fileID); xr.Put(PdfName.W, new PdfArray(new int[]{1, mid, 2})); xr.Put(PdfName.TYPE, PdfName.XREF); PdfArray idx = new PdfArray(); for (int k = 0; k < sections.Count; ++k) idx.Add(new PdfNumber((int)sections[k])); xr.Put(PdfName.INDEX, idx); if (prevxref > 0) xr.Put(PdfName.PREV, new PdfNumber(prevxref)); PdfEncryption enc = writer.crypto; writer.crypto = null; PdfIndirectObject indirect = new PdfIndirectObject(refNumber, xr, writer); indirect.WriteTo(writer.Os); writer.crypto = enc; } else { byte[] tmp = GetISOBytes("xref\n"); os.Write(tmp, 0, tmp.Length); k_Iterator i = xrefs.Begin.Clone(); for (int k = 0; k < sections.Count; k += 2) { first = (int)sections[k]; len = (int)sections[k + 1]; tmp = GetISOBytes(first.ToString()); os.Write(tmp, 0, tmp.Length); os.WriteByte((byte)' '); tmp = GetISOBytes(len.ToString()); os.Write(tmp, 0, tmp.Length); os.WriteByte((byte)'\n'); while (len-- > 0) { entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; entry.ToPdf(os); i.Next(); } } } } } /** * PdfTrailer is the PDF Trailer object. *

* This object is described in the 'Portable Document Format Reference Manual version 1.3' * section 5.16 (page 59-60). */ internal class PdfTrailer : PdfDictionary { // membervariables internal int offset; // constructors /** * Constructs a PDF-Trailer. * * @param size the number of entries in the PdfCrossReferenceTable * @param offset offset of the PdfCrossReferenceTable * @param root an indirect reference to the root of the PDF document * @param info an indirect reference to the info object of the PDF document * @param encryption * @param fileID * @param prevxref */ internal PdfTrailer(int size, int offset, PdfIndirectReference root, PdfIndirectReference info, PdfIndirectReference encryption, PdfObject fileID, int prevxref) { this.offset = offset; Put(PdfName.SIZE, new PdfNumber(size)); Put(PdfName.ROOT, root); if (info != null) { Put(PdfName.INFO, info); } if (encryption != null) Put(PdfName.ENCRYPT, encryption); if (fileID != null) Put(PdfName.ID, fileID); if (prevxref > 0) Put(PdfName.PREV, new PdfNumber(prevxref)); } /** * Returns the PDF representation of this PdfObject. * @param writer * @param os * @throws IOException */ public override void ToPdf(PdfWriter writer, Stream os) { byte[] tmp = GetISOBytes("trailer\n"); os.Write(tmp, 0, tmp.Length); base.ToPdf(null, os); tmp = GetISOBytes("\nstartxref\n"); os.Write(tmp, 0, tmp.Length); tmp = GetISOBytes(offset.ToString()); os.Write(tmp, 0, tmp.Length); tmp = GetISOBytes("\n%%EOF\n"); os.Write(tmp, 0, tmp.Length); } } // ESSENTIALS // Construct a PdfWriter instance /** * Constructs a PdfWriter. */ protected PdfWriter() { root = new PdfPages(this); } /** * Constructs a PdfWriter. *

* Remark: a PdfWriter can only be constructed by calling the method * getInstance(Document document, Stream os). * * @param document The PdfDocument that has to be written * @param os The Stream the writer has to write to. */ protected PdfWriter(PdfDocument document, Stream os) : base(document, os) { root = new PdfPages(this); pdf = document; directContent = new PdfContentByte(this); directContentUnder = new PdfContentByte(this); } // get an instance of the PdfWriter /** * Use this method to get an instance of the PdfWriter. * * @param document The Document that has to be written * @param os The Stream the writer has to write to. * @return a new PdfWriter * * @throws DocumentException on error */ public static PdfWriter GetInstance(Document document, Stream os) { PdfDocument pdf = new PdfDocument(); document.AddDocListener(pdf); PdfWriter writer = new PdfWriter(pdf, os); pdf.AddWriter(writer); return writer; } /** * Use this method to get an instance of the PdfWriter. * * @return a new PdfWriter * @param document The Document that has to be written * @param os The Stream the writer has to write to. * @param listener A DocListener to pass to the PdfDocument. * @throws DocumentException on error */ public static PdfWriter GetInstance(Document document, Stream os, IDocListener listener) { PdfDocument pdf = new PdfDocument(); pdf.AddDocListener(listener); document.AddDocListener(pdf); PdfWriter writer = new PdfWriter(pdf, os); pdf.AddWriter(writer); return writer; } // the PdfDocument instance /** the pdfdocument object. */ protected internal PdfDocument pdf; /** * Gets the PdfDocument associated with this writer. * @return the PdfDocument */ internal PdfDocument PdfDocument { get { return pdf; } } /** * Use this method to get the info dictionary if you want to * change it directly (add keys and values to the info dictionary). * @return the info dictionary */ public PdfDictionary Info { get { return ((PdfDocument)document).Info; } } /** * Use this method to get the current vertical page position. * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects * for elements that do not terminate the lines they've started because those lines will get * terminated. * @return The current vertical page position. */ public float GetVerticalPosition(bool ensureNewLine) { return pdf.GetVerticalPosition(ensureNewLine); } // the PdfDirectContentByte instances /* * You should see Direct Content as a canvas on which you can draw * graphics and text. One canvas goes on top of the page (getDirectContent), * the other goes underneath (getDirectContentUnder). * You can always the same object throughout your document, * even if you have moved to a new page. Whatever you add on * the canvas will be displayed on top or under the current page. */ /** The direct content in this document. */ protected PdfContentByte directContent; /** The direct content under in this document. */ protected PdfContentByte directContentUnder; /** * Use this method to get the direct content for this document. * There is only one direct content, multiple calls to this method * will allways retrieve the same object. * @return the direct content */ public virtual PdfContentByte DirectContent { get { if (!open) throw new Exception("The document is not open."); return directContent; } } /** * Use this method to get the direct content under for this document. * There is only one direct content, multiple calls to this method * will allways retrieve the same object. * @return the direct content */ public virtual PdfContentByte DirectContentUnder { get { if (!open) throw new Exception("The document is not open."); return directContentUnder; } } /** * Resets all the direct contents to empty. * This happens when a new page is started. */ internal void ResetContent() { directContent.Reset(); directContentUnder.Reset(); } // PDF body /* * A PDF file has 4 parts: a header, a body, a cross-reference table, and a trailer. * The body contains all the PDF objects that make up the PDF document. * Each element gets a reference (a set of numbers) and the byte position of * every object is stored in the cross-reference table. * Use these methods only if you know what you're doing. */ /** body of the PDF document */ protected internal PdfBody body; /** * Adds the local destinations to the body of the document. * @param dest the Hashtable containing the destinations * @throws IOException on error */ internal void AddLocalDestinations(k_Tree dest) { foreach (String name in dest.Keys) { Object[] obj = (Object[])dest[name]; PdfDestination destination = (PdfDestination)obj[2]; if (destination == null) throw new Exception("The name '" + name + "' has no local destination."); if (obj[1] == null) obj[1] = PdfIndirectReference; AddToBody(destination, (PdfIndirectReference)obj[1]); } } /** * Adds an object to the PDF body. * @param object * @return a PdfIndirectObject * @throws IOException */ public PdfIndirectObject AddToBody(PdfObject objecta) { PdfIndirectObject iobj = body.Add(objecta); return iobj; } /** * Adds an object to the PDF body. * @param object * @param inObjStm * @return a PdfIndirectObject * @throws IOException */ public PdfIndirectObject AddToBody(PdfObject objecta, bool inObjStm) { PdfIndirectObject iobj = body.Add(objecta, inObjStm); return iobj; } /** * Adds an object to the PDF body. * @param object * @param ref * @return a PdfIndirectObject * @throws IOException */ public PdfIndirectObject AddToBody(PdfObject objecta, PdfIndirectReference refa) { PdfIndirectObject iobj = body.Add(objecta, refa); return iobj; } /** * Adds an object to the PDF body. * @param object * @param ref * @param inObjStm * @return a PdfIndirectObject * @throws IOException */ public PdfIndirectObject AddToBody(PdfObject objecta, PdfIndirectReference refa, bool inObjStm) { PdfIndirectObject iobj = body.Add(objecta, refa, inObjStm); return iobj; } /** * Adds an object to the PDF body. * @param object * @param refNumber * @return a PdfIndirectObject * @throws IOException */ public PdfIndirectObject AddToBody(PdfObject objecta, int refNumber) { PdfIndirectObject iobj = body.Add(objecta, refNumber); return iobj; } /** * Adds an object to the PDF body. * @param object * @param refNumber * @param inObjStm * @return a PdfIndirectObject * @throws IOException */ public PdfIndirectObject AddToBody(PdfObject objecta, int refNumber, bool inObjStm) { PdfIndirectObject iobj = body.Add(objecta, refNumber, inObjStm); return iobj; } /** * Gets a PdfIndirectReference for an object that * will be created in the future. * @return the PdfIndirectReference */ public PdfIndirectReference PdfIndirectReference { get { return body.PdfIndirectReference; } } internal int IndirectReferenceNumber { get { return body.IndirectReferenceNumber; } } /** * Returns the outputStreamCounter. * @return the outputStreamCounter */ internal OutputStreamCounter Os { get { return os; } } // PDF Catalog /* * The Catalog is also called the root object of the document. * Whereas the Cross-Reference maps the objects number with the * byte offset so that the viewer can find the objects, the * Catalog tells the viewer the numbers of the objects needed * to render the document. */ protected virtual PdfDictionary GetCatalog(PdfIndirectReference rootObj) { PdfDictionary catalog = pdf.GetCatalog(rootObj); // [F12] tagged PDF if (tagged) { this.StructureTreeRoot.BuildTree(); catalog.Put(PdfName.STRUCTTREEROOT, structureTreeRoot.Reference); PdfDictionary mi = new PdfDictionary(); mi.Put(PdfName.MARKED, PdfBoolean.PDFTRUE); if (userProperties) mi.Put(PdfName.USERPROPERTIES, PdfBoolean.PDFTRUE); catalog.Put(PdfName.MARKINFO, mi); } // [F13] OCG if (documentOCG.Count != 0) { FillOCProperties(false); catalog.Put(PdfName.OCPROPERTIES, vOCProperties); } return catalog; } /** Holds value of property extraCatalog. */ protected internal PdfDictionary extraCatalog; /** * Sets extra keys to the catalog. * @return the catalog to change */ public PdfDictionary ExtraCatalog { get { if (extraCatalog == null) extraCatalog = new PdfDictionary(); return this.extraCatalog; } } // PdfPages /* * The page root keeps the complete page tree of the document. * There's an entry in the Catalog that refers to the root * of the page tree, the page tree contains the references * to pages and other page trees. */ /** The root of the page tree. */ protected PdfPages root; /** The PdfIndirectReference to the pages. */ protected ArrayList pageReferences = new ArrayList(); /** The current page number. */ protected int currentPageNumber = 1; /** * Use this method to make sure the page tree has a lineair structure * (every leave is attached directly to the root). * Use this method to allow page reordering with method reorderPages. */ public void SetLinearPageMode() { root.SetLinearMode(null); } /** * Use this method to reorder the pages in the document. * A null argument value only returns the number of pages to process. * It is advisable to issue a Document.newPage() before using this method. * @return the total number of pages * @param order an array with the new page sequence. It must have the * same size as the number of pages. * @throws DocumentException if all the pages are not present in the array */ public int ReorderPages(int[] order) { return root.ReorderPages(order); } /** * Use this method to get a reference to a page existing or not. * If the page does not exist yet the reference will be created * in advance. If on closing the document, a page number greater * than the total number of pages was requested, an exception * is thrown. * @param page the page number. The first page is 1 * @return the reference to the page */ public virtual PdfIndirectReference GetPageReference(int page) { --page; if (page < 0) throw new ArgumentOutOfRangeException("The page numbers start at 1."); PdfIndirectReference refa; if (page < pageReferences.Count) { refa = (PdfIndirectReference)pageReferences[page]; if (refa == null) { refa = body.PdfIndirectReference; pageReferences[page] = refa; } } else { int empty = page - pageReferences.Count; for (int k = 0; k < empty; ++k) pageReferences.Add(null); refa = body.PdfIndirectReference; pageReferences.Add(refa); } return refa; } /** * Gets the pagenumber of this document. * This number can be different from the real pagenumber, * if you have (re)set the page number previously. * @return a page number */ public int PageNumber { get { return pdf.PageNumber; } } internal virtual PdfIndirectReference CurrentPage { get { return GetPageReference(currentPageNumber); } } public virtual int CurrentPageNumber { get { return currentPageNumber; } } /** * Adds some PdfContents to this Writer. *

* The document has to be open before you can begin to add content * to the body of the document. * * @return a PdfIndirectReference * @param page the PdfPage to add * @param contents the PdfContents of the page * @throws PdfException on error */ internal virtual PdfIndirectReference Add(PdfPage page, PdfContents contents) { if (!open) { throw new PdfException("The document isn't open."); } PdfIndirectObject objecta; objecta = AddToBody(contents); page.Add(objecta.IndirectReference); if (group != null) { page.Put(PdfName.GROUP, group); group = null; } else if (rgbTransparencyBlending) { PdfDictionary pp = new PdfDictionary(); pp.Put(PdfName.TYPE, PdfName.GROUP); pp.Put(PdfName.S, PdfName.TRANSPARENCY); pp.Put(PdfName.CS, PdfName.DEVICERGB); page.Put(PdfName.GROUP, pp); } root.AddPage(page); currentPageNumber++; return null; } // page events /* * Page events are specific for iText, not for PDF. * Upon specific events (for instance when a page starts * or ends), the corresponing method in the page event * implementation that is added to the writer is invoked. */ /** The PdfPageEvent for this document. */ private IPdfPageEvent pageEvent; /** * Gets the PdfPageEvent for this document or null * if none is set. * @return the PdfPageEvent for this document or null * if none is set */ public IPdfPageEvent PageEvent { get { return pageEvent; } set { if (value == null) this.pageEvent = null; else if (this.pageEvent == null) this.pageEvent = value; else if (this.pageEvent is PdfPageEventForwarder) ((PdfPageEventForwarder)this.pageEvent).AddPageEvent(value); else { PdfPageEventForwarder forward = new PdfPageEventForwarder(); forward.AddPageEvent(this.pageEvent); forward.AddPageEvent(value); this.pageEvent = forward; } } } // Open en Close method + method that create the PDF /** A number refering to the previous Cross-Reference Table. */ protected int prevxref = 0; /** * Signals that the Document has been opened and that * Elements can be added. *

* When this method is called, the PDF-document header is * written to the outputstream. */ public override void Open() { base.Open(); pdf_version.WriteHeader(os); body = new PdfBody(this); if (pdfxConformance.IsPdfX32002()) { PdfDictionary sec = new PdfDictionary(); sec.Put(PdfName.GAMMA, new PdfArray(new float[]{2.2f,2.2f,2.2f})); sec.Put(PdfName.MATRIX, new PdfArray(new float[]{0.4124f,0.2126f,0.0193f,0.3576f,0.7152f,0.1192f,0.1805f,0.0722f,0.9505f})); sec.Put(PdfName.WHITEPOINT, new PdfArray(new float[]{0.9505f,1f,1.089f})); PdfArray arr = new PdfArray(PdfName.CALRGB); arr.Add(sec); SetDefaultColorspace(PdfName.DEFAULTRGB, AddToBody(arr).IndirectReference); } } /** * Signals that the Document was closed and that no other * Elements will be added. *

* The pages-tree is built and written to the outputstream. * A Catalog is constructed, as well as an Info-object, * the referencetable is composed and everything is written * to the outputstream embedded in a Trailer. */ public override void Close() { if (open) { if ((currentPageNumber - 1) != pageReferences.Count) throw new Exception("The page " + pageReferences.Count + " was requested but the document has only " + (currentPageNumber - 1) + " pages."); pdf.Close(); AddSharedObjectsToBody(); // add the root to the body PdfIndirectReference rootRef = root.WritePageTree(); // make the catalog-object and add it to the body PdfDictionary catalog = GetCatalog(rootRef); // [C9] if there is XMP data to add: add it if (xmpMetadata != null) { PdfStream xmp = new PdfStream(xmpMetadata); xmp.Put(PdfName.TYPE, PdfName.METADATA); xmp.Put(PdfName.SUBTYPE, PdfName.XML); if (crypto != null && !crypto.IsMetadataEncrypted()) { PdfArray ar = new PdfArray(); ar.Add(PdfName.CRYPT); xmp.Put(PdfName.FILTER, ar); } catalog.Put(PdfName.METADATA, body.Add(xmp).IndirectReference); } // [C10] make pdfx conformant if (IsPdfX()) { pdfxConformance.CompleteInfoDictionary(Info); pdfxConformance.CompleteExtraCatalog(ExtraCatalog); } // [C11] Output Intents if (extraCatalog != null) { catalog.MergeDifferent(extraCatalog); } WriteOutlines(catalog, false); // add the Catalog to the body PdfIndirectObject indirectCatalog = AddToBody(catalog, false); // add the info-object to the body PdfIndirectObject infoObj = AddToBody(Info, false); // [F1] encryption PdfIndirectReference encryption = null; PdfObject fileID = null; body.FlushObjStm(); if (crypto != null) { PdfIndirectObject encryptionObject = AddToBody(crypto.GetEncryptionDictionary(), false); encryption = encryptionObject.IndirectReference; fileID = crypto.FileID; } else fileID = PdfEncryption.CreateInfoId(PdfEncryption.CreateDocumentId()); // write the cross-reference table of the body body.WriteCrossReferenceTable(os, indirectCatalog.IndirectReference, infoObj.IndirectReference, encryption, fileID, prevxref); // make the trailer // [F2] full compression if (fullCompression) { byte[] tmp = GetISOBytes("startxref\n"); os.Write(tmp, 0, tmp.Length); tmp = GetISOBytes(body.Offset.ToString()); os.Write(tmp, 0, tmp.Length); tmp = GetISOBytes("\n%%EOF\n"); os.Write(tmp, 0, tmp.Length); } else { PdfTrailer trailer = new PdfTrailer(body.Size, body.Offset, indirectCatalog.IndirectReference, infoObj.IndirectReference, encryption, fileID, prevxref); trailer.ToPdf(this, os); } base.Close(); } } protected void AddSharedObjectsToBody() { // add the fonts foreach (FontDetails details in documentFonts.Values) { details.WriteFont(this); } // add the form XObjects foreach (Object[] objs in formXObjects.Values) { PdfTemplate template = (PdfTemplate)objs[1]; if (template != null && template.IndirectReference is PRIndirectReference) continue; if (template != null && template.Type == PdfTemplate.TYPE_TEMPLATE) { AddToBody(template.FormXObject, template.IndirectReference); } } // add all the dependencies in the imported pages foreach (PdfReaderInstance rd in importedPages.Values) { currentPdfReaderInstance = rd; currentPdfReaderInstance.WriteAllPages(); } currentPdfReaderInstance = null; // add the color foreach (ColorDetails color in documentColors.Values) { AddToBody(color.GetSpotColor(this), color.IndirectReference); } // add the pattern foreach (PdfPatternPainter pat in documentPatterns.Keys) { AddToBody(pat.Pattern, pat.IndirectReference); } // add the shading patterns foreach (PdfShadingPattern shadingPattern in documentShadingPatterns.Keys) { shadingPattern.AddToBody(); } // add the shadings foreach (PdfShading shading in documentShadings.Keys) { shading.AddToBody(); } // add the extgstate foreach (DictionaryEntry entry in documentExtGState) { PdfDictionary gstate = (PdfDictionary)entry.Key; PdfObject[] obj = (PdfObject[])entry.Value; AddToBody(gstate, (PdfIndirectReference)obj[1]); } // add the properties foreach (DictionaryEntry entry in documentProperties) { Object prop = entry.Key; PdfObject[] obj = (PdfObject[])entry.Value; if (prop is PdfLayerMembership){ PdfLayerMembership layer = (PdfLayerMembership)prop; AddToBody(layer.PdfObject, layer.Ref); } else if ((prop is PdfDictionary) && !(prop is PdfLayer)){ AddToBody((PdfDictionary)prop, (PdfIndirectReference)obj[1]); } } foreach (IPdfOCG layer in documentOCG.Keys) { AddToBody(layer.PdfObject, layer.Ref); } } // Root data for the PDF document (used when composing the Catalog) // [C1] Outlines (bookmarks) /** * Use this method to get the root outline * and construct bookmarks. * @return the root outline */ public PdfOutline RootOutline { get { return directContent.RootOutline; } } protected ArrayList newBookmarks; /** * Sets the bookmarks. The list structure is defined in * {@link SimpleBookmark}. * @param outlines the bookmarks or null to remove any */ public ArrayList Outlines { set { newBookmarks = value; } } protected internal void WriteOutlines(PdfDictionary catalog, bool namedAsNames) { if (newBookmarks == null || newBookmarks.Count == 0) return; PdfDictionary top = new PdfDictionary(); PdfIndirectReference topRef = this.PdfIndirectReference; Object[] kids = SimpleBookmark.IterateOutlines(this, topRef, newBookmarks, namedAsNames); top.Put(PdfName.FIRST, (PdfIndirectReference)kids[0]); top.Put(PdfName.LAST, (PdfIndirectReference)kids[1]); top.Put(PdfName.COUNT, new PdfNumber((int)kids[2])); AddToBody(top, topRef); catalog.Put(PdfName.OUTLINES, topRef); } // [C2] PdfVersion interface /** possible PDF version (header) */ public const char VERSION_1_2 = '2'; /** possible PDF version (header) */ public const char VERSION_1_3 = '3'; /** possible PDF version (header) */ public const char VERSION_1_4 = '4'; /** possible PDF version (header) */ public const char VERSION_1_5 = '5'; /** possible PDF version (header) */ public const char VERSION_1_6 = '6'; /** possible PDF version (header) */ public const char VERSION_1_7 = '7'; /** possible PDF version (catalog) */ public static readonly PdfName PDF_VERSION_1_2 = new PdfName("1.2"); /** possible PDF version (catalog) */ public static readonly PdfName PDF_VERSION_1_3 = new PdfName("1.3"); /** possible PDF version (catalog) */ public static readonly PdfName PDF_VERSION_1_4 = new PdfName("1.4"); /** possible PDF version (catalog) */ public static readonly PdfName PDF_VERSION_1_5 = new PdfName("1.5"); /** possible PDF version (catalog) */ public static readonly PdfName PDF_VERSION_1_6 = new PdfName("1.6"); /** possible PDF version (catalog) */ public static readonly PdfName PDF_VERSION_1_7 = new PdfName("1.7"); /** Stores the version information for the header and the catalog. */ protected PdfVersionImp pdf_version = new PdfVersionImp(); /** * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(char) */ public virtual char PdfVersion { set { pdf_version.PdfVersion = value; } } /** * @see com.lowagie.text.pdf.interfaces.PdfVersion#setAtLeastPdfVersion(char) */ public void SetAtLeastPdfVersion(char version) { pdf_version.SetAtLeastPdfVersion(version); } /** * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(com.lowagie.text.pdf.PdfName) */ public void SetPdfVersion(PdfName version) { pdf_version.SetPdfVersion(version); } /** * Returns the version information. */ internal PdfVersionImp GetPdfVersion() { return pdf_version; } // [C3] PdfViewerPreferences interface // page layout (section 13.1.1 of "iText in Action") /** A viewer preference */ public const int PageLayoutSinglePage = 1; /** A viewer preference */ public const int PageLayoutOneColumn = 2; /** A viewer preference */ public const int PageLayoutTwoColumnLeft = 4; /** A viewer preference */ public const int PageLayoutTwoColumnRight = 8; /** A viewer preference */ public const int PageLayoutTwoPageLeft = 16; /** A viewer preference */ public const int PageLayoutTwoPageRight = 32; // page mode (section 13.1.2 of "iText in Action") /** A viewer preference */ public const int PageModeUseNone = 64; /** A viewer preference */ public const int PageModeUseOutlines = 128; /** A viewer preference */ public const int PageModeUseThumbs = 256; /** A viewer preference */ public const int PageModeFullScreen = 512; /** A viewer preference */ public const int PageModeUseOC = 1024; /** A viewer preference */ public const int PageModeUseAttachments = 2048; // values for setting viewer preferences in iText versions older than 2.x /** A viewer preference */ public const int HideToolbar = 1 << 12; /** A viewer preference */ public const int HideMenubar = 1 << 13; /** A viewer preference */ public const int HideWindowUI = 1 << 14; /** A viewer preference */ public const int FitWindow = 1 << 15; /** A viewer preference */ public const int CenterWindow = 1 << 16; /** A viewer preference */ public const int DisplayDocTitle = 1 << 17; /** A viewer preference */ public const int NonFullScreenPageModeUseNone = 1 << 18; /** A viewer preference */ public const int NonFullScreenPageModeUseOutlines = 1 << 19; /** A viewer preference */ public const int NonFullScreenPageModeUseThumbs = 1 << 20; /** A viewer preference */ public const int NonFullScreenPageModeUseOC = 1 << 21; /** A viewer preference */ public const int DirectionL2R = 1 << 22; /** A viewer preference */ public const int DirectionR2L = 1 << 23; /** A viewer preference */ public const int PrintScalingNone = 1 << 24; /** * Sets the viewer preferences as the sum of several constants. * @param preferences the viewer preferences * @see PdfViewerPreferences#setViewerPreferences */ public virtual int ViewerPreferences { set { pdf.ViewerPreferences = value; } } /** Adds a viewer preference * @param preferences the viewer preferences * @see PdfViewerPreferences#addViewerPreference */ public virtual void AddViewerPreference(PdfName key, PdfObject value) { pdf.AddViewerPreference(key, value); } // [C4] Page labels /** * Use this method to add page labels * @param pageLabels the page labels */ public virtual PdfPageLabels PageLabels { set { pdf.PageLabels = value; } } // [C5] named objects: named destinations, javascript, embedded files /** * Use this method to add a JavaScript action at the document level. * When the document opens, all this JavaScript runs. * @param js The JavaScript action */ public virtual void AddJavaScript(PdfAction js) { pdf.AddJavaScript(js); } /** Adds a JavaScript action at the document level. When the document * opens all this JavaScript runs. * @param code the JavaScript code * @param unicode select JavaScript unicode. Note that the internal * Acrobat JavaScript engine does not support unicode, * so this may or may not work for you */ public virtual void AddJavaScript(String code, bool unicode) { AddJavaScript(PdfAction.JavaScript(code, this, unicode)); } /** Adds a JavaScript action at the document level. When the document * opens all this JavaScript runs. * @param code the JavaScript code */ public virtual void AddJavaScript(String code) { AddJavaScript(code, false); } /** * Use this method to add a JavaScript action at the document level. * When the document opens, all this JavaScript runs. * @param name The name of the JS Action in the name tree * @param js The JavaScript action */ public void AddJavaScript(String name, PdfAction js) { pdf.AddJavaScript(name, js); } /** * Use this method to add a JavaScript action at the document level. * When the document opens, all this JavaScript runs. * @param name The name of the JS Action in the name tree * @param code the JavaScript code * @param unicode select JavaScript unicode. Note that the internal * Acrobat JavaScript engine does not support unicode, * so this may or may not work for you */ public void AddJavaScript(String name, String code, bool unicode) { AddJavaScript(name, PdfAction.JavaScript(code, this, unicode)); } /** * Use this method to adds a JavaScript action at the document level. * When the document opens, all this JavaScript runs. * @param name The name of the JS Action in the name tree * @param code the JavaScript code */ public void AddJavaScript(String name, String code) { AddJavaScript(name, code, false); } /** Adds a file attachment at the document level. * @param description the file description * @param fileStore an array with the file. If it's null * the file will be read from the disk * @param file the path to the file. It will only be used if * fileStore is not null * @param fileDisplay the actual file name stored in the pdf * @throws IOException on error */ public virtual void AddFileAttachment(String description, byte[] fileStore, String file, String fileDisplay) { AddFileAttachment(description, PdfFileSpecification.FileEmbedded(this, file, fileDisplay, fileStore)); } /** Adds a file attachment at the document level. * @param description the file description * @param fs the file specification */ public virtual void AddFileAttachment(String description, PdfFileSpecification fs) { pdf.AddFileAttachment(description, fs); } /** Adds a file attachment at the document level. * @param fs the file specification */ public void AddFileAttachment(PdfFileSpecification fs) { pdf.AddFileAttachment(null, fs); } // [C6] Actions (open and additional) /** action value */ public static PdfName DOCUMENT_CLOSE = PdfName.WC; /** action value */ public static PdfName WILL_SAVE = PdfName.WS; /** action value */ public static PdfName DID_SAVE = PdfName.DS; /** action value */ public static PdfName WILL_PRINT = PdfName.WP; /** action value */ public static PdfName DID_PRINT = PdfName.DP; /** When the document opens it will jump to the destination with * this name. * @param name the name of the destination to jump to */ public virtual void SetOpenAction(String name) { pdf.SetOpenAction(name); } /** When the document opens this action will be * invoked. * @param action the action to be invoked */ public virtual void SetOpenAction(PdfAction action) { pdf.SetOpenAction(action); } /** Additional-actions defining the actions to be taken in * response to various trigger events affecting the document * as a whole. The actions types allowed are: DOCUMENT_CLOSE, * WILL_SAVE, DID_SAVE, WILL_PRINT * and DID_PRINT. * * @param actionType the action type * @param action the action to execute in response to the trigger * @throws PdfException on invalid action type */ public virtual void SetAdditionalAction(PdfName actionType, PdfAction action) { if (!(actionType.Equals(DOCUMENT_CLOSE) || actionType.Equals(WILL_SAVE) || actionType.Equals(DID_SAVE) || actionType.Equals(WILL_PRINT) || actionType.Equals(DID_PRINT))) { throw new PdfException("Invalid additional action type: " + actionType.ToString()); } pdf.AddAdditionalAction(actionType, action); } // [C7] portable collections /** * Sets the Collection dictionary. * @param collection a dictionary of type PdfCollection */ public PdfCollection Collection { set { SetAtLeastPdfVersion(VERSION_1_7); pdf.Collection = value; } } // [C8] AcroForm /** signature value */ public const int SIGNATURE_EXISTS = 1; /** signature value */ public const int SIGNATURE_APPEND_ONLY = 2; /** Gets the AcroForm object. * @return the PdfAcroForm */ public PdfAcroForm AcroForm { get { return pdf.AcroForm; } } /** Adds a PdfAnnotation or a PdfFormField * to the document. Only the top parent of a PdfFormField * needs to be added. * @param annot the PdfAnnotation or the PdfFormField to add */ public virtual void AddAnnotation(PdfAnnotation annot) { pdf.AddAnnotation(annot); } internal virtual void AddAnnotation(PdfAnnotation annot, int page) { AddAnnotation(annot); } /** Adds the PdfAnnotation to the calculation order * array. * @param annot the PdfAnnotation to be added */ public virtual void AddCalculationOrder(PdfFormField annot) { pdf.AddCalculationOrder(annot); } /** Set the signature flags. * @param f the flags. This flags are ORed with current ones */ public virtual int SigFlags { set { pdf.SigFlags = value; } } // [C9] Metadata /** XMP Metadata for the document. */ protected byte[] xmpMetadata = null; /** * Sets XMP Metadata. * @param xmpMetadata The xmpMetadata to set. */ public byte[] XmpMetadata { set { this.xmpMetadata = value; } get { return this.xmpMetadata; } } /** * Use this method to set the XMP Metadata for each page. * @param xmpMetadata The xmpMetadata to set. */ public byte[] PageXmpMetadata { set { pdf.XmpMetadata = value; } } /** * Creates XMP Metadata based on the metadata in the PdfDocument. */ public void CreateXmpMetadata() { XmpMetadata = CreateXmpMetadataBytes(); } /** * @return an XmpMetadata byte array */ private byte[] CreateXmpMetadataBytes() { MemoryStream baos = new MemoryStream(); try { XmpWriter xmp = new XmpWriter(baos, pdf.Info, pdfxConformance.PDFXConformance); xmp.Close(); } catch(IOException) { } return baos.ToArray(); } // [C10] PDFX Conformance /** PDF/X level */ public const int PDFXNONE = 0; /** PDF/X level */ public const int PDFX1A2001 = 1; /** PDF/X level */ public const int PDFX32002 = 2; /** PDFA-1A level. */ public const int PDFA1A = 3; /** PDFA-1B level. */ public const int PDFA1B = 4; /** Stores the PDF/X level. */ private PdfXConformanceImp pdfxConformance = new PdfXConformanceImp(); /** * Sets the PDFX conformance level. Allowed values are PDFX1A2001 and PDFX32002. It * must be called before opening the document. * @param pdfxConformance the conformance level */ public int PDFXConformance { set { if (pdfxConformance.PDFXConformance == value) return; if (pdf.IsOpen()) throw new PdfXConformanceException("PDFX conformance can only be set before opening the document."); if (crypto != null) throw new PdfXConformanceException("A PDFX conforming document cannot be encrypted."); if (value == PDFA1A || value == PDFA1B) PdfVersion = VERSION_1_4; else if (value != PDFXNONE) PdfVersion = VERSION_1_3; pdfxConformance.PDFXConformance = value; } get { return pdfxConformance.PDFXConformance; } } /** @see com.lowagie.text.pdf.interfaces.PdfXConformance#isPdfX() */ public bool IsPdfX() { return pdfxConformance.IsPdfX(); } // [C11] Output intents /** * Sets the values of the output intent dictionary. Null values are allowed to * suppress any key. * @param outputConditionIdentifier a value * @param outputCondition a value * @param registryName a value * @param info a value * @param destOutputProfile a value * @throws IOException on error */ public void SetOutputIntents(String outputConditionIdentifier, String outputCondition, String registryName, String info, byte[] destOutputProfile) { PdfDictionary outa = ExtraCatalog; //force the creation outa = new PdfDictionary(PdfName.OUTPUTINTENT); if (outputCondition != null) outa.Put(PdfName.OUTPUTCONDITION, new PdfString(outputCondition, PdfObject.TEXT_UNICODE)); if (outputConditionIdentifier != null) outa.Put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString(outputConditionIdentifier, PdfObject.TEXT_UNICODE)); if (registryName != null) outa.Put(PdfName.REGISTRYNAME, new PdfString(registryName, PdfObject.TEXT_UNICODE)); if (info != null) outa.Put(PdfName.INFO, new PdfString(info, PdfObject.TEXT_UNICODE)); if (destOutputProfile != null) { PdfStream stream = new PdfStream(destOutputProfile); stream.FlateCompress(); outa.Put(PdfName.DESTOUTPUTPROFILE, AddToBody(stream).IndirectReference); } outa.Put(PdfName.S, PdfName.GTS_PDFX); extraCatalog.Put(PdfName.OUTPUTINTENTS, new PdfArray(outa)); } /** * Copies the output intent dictionary from other document to this one. * @param reader the other document * @param checkExistence true to just check for the existence of a valid output intent * dictionary, false to insert the dictionary if it exists * @throws IOException on error * @return true if the output intent dictionary exists, false * otherwise */ public bool SetOutputIntents(PdfReader reader, bool checkExistence) { PdfDictionary catalog = reader.Catalog; PdfArray outs = (PdfArray)PdfReader.GetPdfObject(catalog.Get(PdfName.OUTPUTINTENTS)); if (outs == null) return false; ArrayList arr = outs.ArrayList; if (arr.Count == 0) return false; PdfDictionary outa = (PdfDictionary)PdfReader.GetPdfObject((PdfObject)arr[0]); PdfObject obj = PdfReader.GetPdfObject(outa.Get(PdfName.S)); if (obj == null || !PdfName.GTS_PDFX.Equals(obj)) return false; if (checkExistence) return true; PRStream stream = (PRStream)PdfReader.GetPdfObject(outa.Get(PdfName.DESTOUTPUTPROFILE)); byte[] destProfile = null; if (stream != null) { destProfile = PdfReader.GetStreamBytes(stream); } SetOutputIntents(GetNameString(outa, PdfName.OUTPUTCONDITIONIDENTIFIER), GetNameString(outa, PdfName.OUTPUTCONDITION), GetNameString(outa, PdfName.REGISTRYNAME), GetNameString(outa, PdfName.INFO), destProfile); return true; } private static String GetNameString(PdfDictionary dic, PdfName key) { PdfObject obj = PdfReader.GetPdfObject(dic.Get(key)); if (obj == null || !obj.IsString()) return null; return ((PdfString)obj).ToUnicodeString(); } // PDF Objects that have an impact on the PDF body // [F1] PdfEncryptionSettings interface // types of encryption /** Type of encryption */ public const int STANDARD_ENCRYPTION_40 = 0; /** Type of encryption */ public const int STANDARD_ENCRYPTION_128 = 1; /** Type of encryption */ public const int ENCRYPTION_AES_128 = 2; /** Mask to separate the encryption type from the encryption mode. */ internal const int ENCRYPTION_MASK = 7; /** Add this to the mode to keep the metadata in clear text */ public const int DO_NOT_ENCRYPT_METADATA = 8; // permissions /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_PRINTING = 4 + 2048; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_MODIFY_CONTENTS = 8; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_COPY = 16; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_MODIFY_ANNOTATIONS = 32; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_FILL_IN = 256; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_SCREENREADERS = 512; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_ASSEMBLY = 1024; /** The operation permitted when the document is opened with the user password * * @since 2.0.7 */ public const int ALLOW_DEGRADED_PRINTING = 4; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_PRINTING} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowPrinting = ALLOW_PRINTING; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_MODIFY_CONTENTS} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowModifyContents = ALLOW_MODIFY_CONTENTS; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_COPY} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowCopy = ALLOW_COPY; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_MODIFY_ANNOTATIONS} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowModifyAnnotations = ALLOW_MODIFY_ANNOTATIONS; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_FILL_IN} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowFillIn = ALLOW_FILL_IN; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_SCREENREADERS} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowScreenReaders = ALLOW_SCREENREADERS; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_ASSEMBLY} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowAssembly = ALLOW_ASSEMBLY; /** @deprecated As of iText 2.0.7, use {@link #ALLOW_DEGRADED_PRINTING} instead. Scheduled for removal at or after 2.2.0 */ public const int AllowDegradedPrinting = ALLOW_DEGRADED_PRINTING; // Strength of the encryption (kept for historical reasons) /** @deprecated As of iText 2.0.7, use {@link #STANDARD_ENCRYPTION_40} instead. Scheduled for removal at or after 2.2.0 */ public const bool STRENGTH40BITS = false; /** @deprecated As of iText 2.0.7, use {@link #STANDARD_ENCRYPTION_128} instead. Scheduled for removal at or after 2.2.0 */ public const bool STRENGTH128BITS = true; /** Contains the business logic for cryptography. */ protected PdfEncryption crypto; internal PdfEncryption Encryption { get { return crypto; } } /** Sets the encryption options for this document. The userPassword and the * ownerPassword can be null or have zero length. In this case the ownerPassword * is replaced by a random string. The open permissions for the document can be * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. * The permissions can be combined by ORing them. * @param userPassword the user password. Can be null or empty * @param ownerPassword the owner password. Can be null or empty * @param permissions the user permissions * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext * @throws DocumentException if the document is already open */ public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { if (pdf.IsOpen()) throw new DocumentException("Encryption can only be added before opening the document."); crypto = new PdfEncryption(); crypto.SetCryptoMode(encryptionType, 0); crypto.SetupAllKeys(userPassword, ownerPassword, permissions); } /** * Sets the certificate encryption options for this document. An array of one or more public certificates * must be provided together with an array of the same size for the permissions for each certificate. * The open permissions for the document can be * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. * The permissions can be combined by ORing them. * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext * @param certs the public certificates to be used for the encryption * @param permissions the user permissions for each of the certicates * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. * @throws DocumentException if the document is already open */ public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { if (pdf.IsOpen()) throw new DocumentException("Encryption can only be added before opening the document."); crypto = new PdfEncryption(); if (certs != null) { for (int i=0; i < certs.Length; i++) { crypto.AddRecipient(certs[i], permissions[i]); } } crypto.SetCryptoMode(encryptionType, 0); crypto.GetEncryptionDictionary(); } /** Sets the encryption options for this document. The userPassword and the * ownerPassword can be null or have zero length. In this case the ownerPassword * is replaced by a random string. The open permissions for the document can be * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. * The permissions can be combined by ORing them. * @param userPassword the user password. Can be null or empty * @param ownerPassword the owner password. Can be null or empty * @param permissions the user permissions * @param strength128Bits true for 128 bit key length, false for 40 bit key length * @throws DocumentException if the document is already open */ public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? STANDARD_ENCRYPTION_128 : STANDARD_ENCRYPTION_40); } /** * Sets the encryption options for this document. The userPassword and the * ownerPassword can be null or have zero length. In this case the ownerPassword * is replaced by a random string. The open permissions for the document can be * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. * The permissions can be combined by ORing them. * @param strength true for 128 bit key length, false for 40 bit key length * @param userPassword the user password. Can be null or empty * @param ownerPassword the owner password. Can be null or empty * @param permissions the user permissions * @throws DocumentException if the document is already open */ public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { SetEncryption(GetISOBytes(userPassword), GetISOBytes(ownerPassword), permissions, strength); } /** * Sets the encryption options for this document. The userPassword and the * ownerPassword can be null or have zero length. In this case the ownerPassword * is replaced by a random string. The open permissions for the document can be * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. * The permissions can be combined by ORing them. * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext * @param userPassword the user password. Can be null or empty * @param ownerPassword the owner password. Can be null or empty * @param permissions the user permissions * @throws DocumentException if the document is already open */ public void SetEncryption(int encryptionType, String userPassword, String ownerPassword, int permissions) { SetEncryption(GetISOBytes(userPassword), GetISOBytes(ownerPassword), permissions, encryptionType); } // [F2] compression /** * Holds value of property fullCompression. */ protected bool fullCompression = false; /** * Gets the 1.5 compression status. * @return true if the 1.5 compression is on */ public bool FullCompression { get { return this.fullCompression; } } /** * Sets the document's compression to the new 1.5 mode with object streams and xref * streams. It can be set at any time but once set it can't be unset. *

* If set before opening the document it will also set the pdf version to 1.5. */ public void SetFullCompression() { this.fullCompression = true; SetAtLeastPdfVersion(VERSION_1_5); } // [F3] adding fonts /** The fonts of this document */ protected Hashtable documentFonts = new Hashtable(); /** The font number counter for the fonts in the document. */ protected int fontNumber = 1; /** * Adds a BaseFont to the document but not to the page resources. * It is used for templates. * @param bf the BaseFont to add * @return an Object[] where position 0 is a PdfName * and position 1 is an PdfIndirectReference */ internal FontDetails AddSimple(BaseFont bf) { if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { return new FontDetails(new PdfName("F" + (fontNumber++)), ((DocumentFont)bf).IndirectReference, bf); } FontDetails ret = (FontDetails)documentFonts[bf]; if (ret == null) { PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_FONT, bf); ret = new FontDetails(new PdfName("F" + (fontNumber++)), body.PdfIndirectReference, bf); documentFonts[bf] = ret; } return ret; } internal void EliminateFontSubset(PdfDictionary fonts) { foreach (FontDetails ft in documentFonts.Values) { if (fonts.Get(ft.FontName) != null) ft.Subset = false; } } // [F4] adding (and releasing) form XObjects /** The form XObjects in this document. The key is the xref and the value is Object[]{PdfName, template}.*/ protected Hashtable formXObjects = new Hashtable(); /** The name counter for the form XObjects name. */ protected int formXObjectsCounter = 1; /** * Adds a template to the document but not to the page resources. * @param template the template to add * @param forcedName the template name, rather than a generated one. Can be null * @return the PdfName for this template */ internal PdfName AddDirectTemplateSimple(PdfTemplate template, PdfName forcedName) { PdfIndirectReference refa = template.IndirectReference; Object[] obj = (Object[])formXObjects[refa]; PdfName name = null; if (obj == null) { if (forcedName == null) { name = new PdfName("Xf" + formXObjectsCounter); ++formXObjectsCounter; } else name = forcedName; if (template.Type == PdfTemplate.TYPE_IMPORTED) { // If we got here from PdfCopy we'll have to fill importedPages PdfImportedPage ip = (PdfImportedPage)template; PdfReader r = ip.PdfReaderInstance.Reader; if (!importedPages.ContainsKey(r)) { importedPages[r] = ip.PdfReaderInstance; } template = null; } formXObjects[refa] = new Object[]{name, template}; } else name = (PdfName)obj[0]; return name; } /** * Releases the memory used by a template by writing it to the output. The template * can still be added to any content but changes to the template itself won't have * any effect. * @param tp the template to release * @throws IOException on error */ public void ReleaseTemplate(PdfTemplate tp) { PdfIndirectReference refi = tp.IndirectReference; Object[] objs = (Object[])formXObjects[refi]; if (objs == null || objs[1] == null) return; PdfTemplate template = (PdfTemplate)objs[1]; if (template.IndirectReference is PRIndirectReference) return; if (template.Type == PdfTemplate.TYPE_TEMPLATE) { AddToBody(template.FormXObject, template.IndirectReference); objs[1] = null; } } // [F5] adding pages imported form other PDF documents protected Hashtable importedPages = new Hashtable(); /** Gets a page from other PDF document. The page can be used as * any other PdfTemplate. Note that calling this method more than * once with the same parameters will retrieve the same object. * @param reader the PDF document where the page is * @param pageNumber the page number. The first page is 1 * @return the template representing the imported page */ public virtual PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { PdfReaderInstance inst = (PdfReaderInstance)importedPages[reader]; if (inst == null) { inst = reader.GetPdfReaderInstance(this); importedPages[reader] = inst; } return inst.GetImportedPage(pageNumber); } /** Writes the reader to the document and frees the memory used by it. * The main use is when concatenating multiple documents to keep the * memory usage restricted to the current appending document. * @param reader the PdfReader to free * @throws IOException on error */ public virtual void FreeReader(PdfReader reader) { currentPdfReaderInstance = (PdfReaderInstance)importedPages[reader]; if (currentPdfReaderInstance == null) return; currentPdfReaderInstance.WriteAllPages(); currentPdfReaderInstance = null; importedPages.Remove(reader); } /** Gets the current document size. This size only includes * the data already writen to the output stream, it does not * include templates or fonts. It is usefull if used with * freeReader() when concatenating many documents * and an idea of the current size is needed. * @return the approximate size without fonts or templates */ public int CurrentDocumentSize { get { return body.Offset + body.Size * 20 + 0x48; } } protected PdfReaderInstance currentPdfReaderInstance; protected internal virtual int GetNewObjectNumber(PdfReader reader, int number, int generation) { return currentPdfReaderInstance.GetNewObjectNumber(number, generation); } internal virtual RandomAccessFileOrArray GetReaderFile(PdfReader reader) { return currentPdfReaderInstance.ReaderFile; } // [F6] spot colors /** The colors of this document */ protected Hashtable documentColors = new Hashtable(); /** The color number counter for the colors in the document. */ protected int colorNumber = 1; internal PdfName GetColorspaceName() { return new PdfName("CS" + (colorNumber++)); } /** * Adds a SpotColor to the document but not to the page resources. * @param spc the SpotColor to add * @return an Object[] where position 0 is a PdfName * and position 1 is an PdfIndirectReference */ internal ColorDetails AddSimple(PdfSpotColor spc) { ColorDetails ret = (ColorDetails)documentColors[spc]; if (ret == null) { ret = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, spc); documentColors[spc] = ret; } return ret; } // [F7] document patterns /** The patterns of this document */ protected Hashtable documentPatterns = new Hashtable(); /** The patten number counter for the colors in the document. */ protected int patternNumber = 1; internal PdfName AddSimplePattern(PdfPatternPainter painter) { PdfName name = (PdfName)documentPatterns[painter]; if ( name == null ) { name = new PdfName("P" + patternNumber); ++patternNumber; documentPatterns[painter] = name; } return name; } // [F8] shading patterns protected Hashtable documentShadingPatterns = new Hashtable(); internal void AddSimpleShadingPattern(PdfShadingPattern shading) { if (!documentShadingPatterns.ContainsKey(shading)) { shading.Name = patternNumber; ++patternNumber; documentShadingPatterns[shading] = null; AddSimpleShading(shading.Shading); } } // [F9] document shadings protected Hashtable documentShadings = new Hashtable(); internal void AddSimpleShading(PdfShading shading) { if (!documentShadings.ContainsKey(shading)) { documentShadings[shading] = null; shading.Name = documentShadings.Count; } } // [F10] extended graphics state (for instance for transparency) protected Hashtable documentExtGState = new Hashtable(); internal PdfObject[] AddSimpleExtGState(PdfDictionary gstate) { if (!documentExtGState.ContainsKey(gstate)) { PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_GSTATE, gstate); documentExtGState[gstate] = new PdfObject[]{new PdfName("GS" + (documentExtGState.Count + 1)), PdfIndirectReference}; } return (PdfObject[])documentExtGState[gstate]; } // [F11] adding properties (OCG, marked content) protected Hashtable documentProperties = new Hashtable(); internal PdfObject[] AddSimpleProperty(Object prop, PdfIndirectReference refi) { if (!documentProperties.ContainsKey(prop)) { if (prop is IPdfOCG) PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_LAYER, null); documentProperties[prop] = new PdfObject[]{new PdfName("Pr" + (documentProperties.Count + 1)), refi}; } return (PdfObject[])documentProperties[prop]; } internal bool PropertyExists(Object prop) { return documentProperties.ContainsKey(prop); } // [F12] tagged PDF protected bool tagged = false; protected PdfStructureTreeRoot structureTreeRoot; /** * Mark this document for tagging. It must be called before open. */ public void SetTagged() { if (open) throw new ArgumentException("Tagging must be set before opening the document."); tagged = true; } /** * Check if the document is marked for tagging. * @return true if the document is marked for tagging */ public bool IsTagged() { return tagged; } /** * Gets the structure tree root. If the document is not marked for tagging it will return null. * @return the structure tree root */ public PdfStructureTreeRoot StructureTreeRoot { get { if (tagged && structureTreeRoot == null) structureTreeRoot = new PdfStructureTreeRoot(this); return structureTreeRoot; } } // [F13] Optional Content Groups protected Hashtable documentOCG = new Hashtable(); protected ArrayList documentOCGorder = new ArrayList(); protected PdfOCProperties vOCProperties; protected PdfArray OCGRadioGroup = new PdfArray(); protected PdfArray OCGLocked = new PdfArray(); /** * Gets the Optional Content Properties Dictionary. Each call fills the dictionary with the current layer * state. It's advisable to only call this method right before close and do any modifications * at that time. * @return the Optional Content Properties Dictionary */ public PdfOCProperties OCProperties { get { FillOCProperties(true); return vOCProperties; } } /** * Sets a collection of optional content groups whose states are intended to follow * a "radio button" paradigm. That is, the state of at most one optional * content group in the array should be ON at a time: if one group is turned * ON, all others must be turned OFF. * @param group the radio group */ public void AddOCGRadioGroup(ArrayList group) { PdfArray ar = new PdfArray(); for (int k = 0; k < group.Count; ++k) { PdfLayer layer = (PdfLayer)group[k]; if (layer.Title == null) ar.Add(layer.Ref); } if (ar.Size == 0) return; OCGRadioGroup.Add(ar); } /** * Use this method to lock an optional content group. * The state of a locked group cannot be changed through the user interface * of a viewer application. Producers can use this entry to prevent the visibility * of content that depends on these groups from being changed by users. * @param layer the layer that needs to be added to the array of locked OCGs * @since 2.1.2 */ public void LockLayer(PdfLayer layer) { OCGLocked.Add(layer.Ref); } private static void GetOCGOrder(PdfArray order, PdfLayer layer) { if (!layer.OnPanel) return; if (layer.Title == null) order.Add(layer.Ref); ArrayList children = layer.Children; if (children == null) return; PdfArray kids = new PdfArray(); if (layer.Title != null) kids.Add(new PdfString(layer.Title, PdfObject.TEXT_UNICODE)); for (int k = 0; k < children.Count; ++k) { GetOCGOrder(kids, (PdfLayer)children[k]); } if (kids.Size > 0) order.Add(kids); } private void AddASEvent(PdfName eventa, PdfName category) { PdfArray arr = new PdfArray(); foreach (PdfLayer layer in documentOCG.Keys) { PdfDictionary usage = (PdfDictionary)layer.Get(PdfName.USAGE); if (usage != null && usage.Get(category) != null) arr.Add(layer.Ref); } if (arr.Size == 0) return; PdfDictionary d = (PdfDictionary)vOCProperties.Get(PdfName.D); PdfArray arras = (PdfArray)d.Get(PdfName.AS); if (arras == null) { arras = new PdfArray(); d.Put(PdfName.AS, arras); } PdfDictionary asa = new PdfDictionary(); asa.Put(PdfName.EVENT, eventa); asa.Put(PdfName.CATEGORY, new PdfArray(category)); asa.Put(PdfName.OCGS, arr); arras.Add(asa); } protected void FillOCProperties(bool erase) { if (vOCProperties == null) vOCProperties = new PdfOCProperties(); if (erase) { vOCProperties.Remove(PdfName.OCGS); vOCProperties.Remove(PdfName.D); } if (vOCProperties.Get(PdfName.OCGS) == null) { PdfArray gr = new PdfArray(); foreach (PdfLayer layer in documentOCG.Keys) { gr.Add(layer.Ref); } vOCProperties.Put(PdfName.OCGS, gr); } if (vOCProperties.Get(PdfName.D) != null) return; ArrayList docOrder = new ArrayList(documentOCGorder); for (ListIterator it = new ListIterator(docOrder); it.HasNext();) { PdfLayer layer = (PdfLayer)it.Next(); if (layer.Parent != null) it.Remove(); } PdfArray order = new PdfArray(); foreach (PdfLayer layer in docOrder) { GetOCGOrder(order, layer); } PdfDictionary d = new PdfDictionary(); vOCProperties.Put(PdfName.D, d); d.Put(PdfName.ORDER, order); PdfArray grx = new PdfArray(); foreach (PdfLayer layer in documentOCG.Keys) { if (!layer.On) grx.Add(layer.Ref); } if (grx.Size > 0) d.Put(PdfName.OFF, grx); if (OCGRadioGroup.Size > 0) d.Put(PdfName.RBGROUPS, OCGRadioGroup); if (OCGLocked.Size > 0) d.Put(PdfName.LOCKED, OCGLocked); AddASEvent(PdfName.VIEW, PdfName.ZOOM); AddASEvent(PdfName.VIEW, PdfName.VIEW); AddASEvent(PdfName.PRINT, PdfName.PRINT); AddASEvent(PdfName.EXPORT, PdfName.EXPORT); d.Put(PdfName.LISTMODE, PdfName.VISIBLEPAGES); } internal void RegisterLayer(IPdfOCG layer) { PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_LAYER, null); if (layer is PdfLayer) { PdfLayer la = (PdfLayer)layer; if (la.Title == null) { if (!documentOCG.ContainsKey(layer)) { documentOCG[layer] = null; documentOCGorder.Add(layer); } } else { documentOCGorder.Add(layer); } } else throw new ArgumentException("Only PdfLayer is accepted."); } // User methods to change aspects of the page // [U1] page size /** * Gives the size of the media box. * @return a Rectangle */ public Rectangle PageSize { get { return pdf.PageSize; } } /** Sets the crop box. The crop box should not be rotated even if the * page is rotated. This change only takes effect in the next * page. * @param crop the crop box */ public virtual Rectangle CropBoxSize { set { pdf.CropBoxSize = value; } } /** * Sets the page box sizes. Allowed names are: "crop", "trim", "art" and "bleed". * @param boxName the box size * @param size the size */ public void SetBoxSize(String boxName, Rectangle size) { pdf.SetBoxSize(boxName, size); } /** * Gives the size of a trim, art, crop or bleed box, or null if not defined. * @param boxName crop, trim, art or bleed */ public Rectangle GetBoxSize(String boxName) { return pdf.GetBoxSize(boxName); } // [U2] take care of empty pages /** * If you use SetPageEmpty(false), invoking NewPage() after a blank page will add a newPage. * @param pageEmpty the state */ public bool PageEmpty { set { pdf.PageEmpty = value; } } // [U3] page actions (open and close) /** action value */ public static readonly PdfName PAGE_OPEN = PdfName.O; /** action value */ public static readonly PdfName PAGE_CLOSE = PdfName.C; /** Sets the open and close page additional action. * @param actionType the action type. It can be PdfWriter.PAGE_OPEN * or PdfWriter.PAGE_CLOSE * @param action the action to perform * @throws PdfException if the action type is invalid */ public virtual void SetPageAction(PdfName actionType, PdfAction action) { if (!actionType.Equals(PAGE_OPEN) && !actionType.Equals(PAGE_CLOSE)) throw new PdfException("Invalid page additional action type: " + actionType.ToString()); pdf.SetPageAction(actionType, action); } /** * Sets the display duration for the page (for presentations) * @param seconds the number of seconds to display the page */ public virtual int Duration { set { pdf.Duration = value; } } /** * Sets the transition for the page * @param transition the Transition object */ public virtual PdfTransition Transition { set { pdf.Transition = value; } } // [U4] Thumbnail image /** * Sets the the thumbnail image for the current page. * @param image the image * @throws PdfException on error * @throws DocumentException or error */ public virtual Image Thumbnail { set { pdf.Thumbnail = value; } } // [U5] Transparency groups /** * A group attributes dictionary specifying the attributes * of the page’s page group for use in the transparent * imaging model */ protected PdfDictionary group; public PdfDictionary Group { get { return this.group; } set { group = value; } } // [U6] space char ratio /** The default space-char ratio. */ public const float SPACE_CHAR_RATIO_DEFAULT = 2.5f; /** Disable the inter-character spacing. */ public const float NO_SPACE_CHAR_RATIO = 10000000f; /** * The ratio between the extra word spacing and the extra character spacing. * Extra word spacing will grow ratio times more than extra character spacing. */ private float spaceCharRatio = SPACE_CHAR_RATIO_DEFAULT; /** Sets the ratio between the extra word spacing and the extra character spacing * when the text is fully justified. * Extra word spacing will grow spaceCharRatio times more than extra character spacing. * If the ratio is PdfWriter.NO_SPACE_CHAR_RATIO then the extra character spacing * will be zero. * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing */ public virtual float SpaceCharRatio { set { if (value < 0.001f) this.spaceCharRatio = 0.001f; else this.spaceCharRatio = value; } get { return spaceCharRatio; } } // [U7] run direction (doesn't actually do anything) /** Use the default run direction. */ public const int RUN_DIRECTION_DEFAULT = 0; /** Do not use bidirectional reordering. */ public const int RUN_DIRECTION_NO_BIDI = 1; /** Use bidirectional reordering with left-to-right * preferential run direction. */ public const int RUN_DIRECTION_LTR = 2; /** Use bidirectional reordering with right-to-left * preferential run direction. */ public const int RUN_DIRECTION_RTL = 3; protected int runDirection = RUN_DIRECTION_NO_BIDI; /** Sets the run direction. This is only used as a placeholder * as it does not affect anything. * @param runDirection the run direction */ public virtual int RunDirection { set { if (value < RUN_DIRECTION_NO_BIDI || value > RUN_DIRECTION_RTL) throw new Exception("Invalid run direction: " + value); this.runDirection = value; } get { return runDirection; } } // [U8] user units protected float userunit = 0f; /** * A UserUnit is a value that defines the default user space unit. * The minimum UserUnit is 1 (1 unit = 1/72 inch). * The maximum UserUnit is 75,000. * Remark that this userunit only works starting with PDF1.6! */ public float Userunit { get { return userunit; } set { if (value < 1f || value > 75000f) throw new DocumentException("UserUnit should be a value between 1 and 75000."); this.userunit = value; SetAtLeastPdfVersion(VERSION_1_6); } } // Miscellaneous topics // [M1] Color settings protected PdfDictionary defaultColorspace = new PdfDictionary(); /** * Gets the default colorspaces. * @return the default colorspaces */ public PdfDictionary DefaultColorspace { get { return defaultColorspace; } } /** * Sets the default colorspace that will be applied to all the document. * The colorspace is only applied if another colorspace with the same name * is not present in the content. *

* The colorspace is applied immediately when creating templates and at the page * end for the main document content. * @param key the name of the colorspace. It can be PdfName.DEFAULTGRAY, PdfName.DEFAULTRGB * or PdfName.DEFAULTCMYK * @param cs the colorspace. A null or PdfNull removes any colorspace with the same name */ public void SetDefaultColorspace(PdfName key, PdfObject cs) { if (cs == null || cs.IsNull()) defaultColorspace.Remove(key); defaultColorspace.Put(key, cs); } // [M2] spot patterns protected Hashtable documentSpotPatterns = new Hashtable(); protected ColorDetails patternColorspaceRGB; protected ColorDetails patternColorspaceGRAY; protected ColorDetails patternColorspaceCMYK; internal ColorDetails AddSimplePatternColorspace(Color color) { int type = ExtendedColor.GetType(color); if (type == ExtendedColor.TYPE_PATTERN || type == ExtendedColor.TYPE_SHADING) throw new Exception("An uncolored tile pattern can not have another pattern or shading as color."); switch (type) { case ExtendedColor.TYPE_RGB: if (patternColorspaceRGB == null) { patternColorspaceRGB = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); PdfArray array = new PdfArray(PdfName.PATTERN); array.Add(PdfName.DEVICERGB); AddToBody(array, patternColorspaceRGB.IndirectReference); } return patternColorspaceRGB; case ExtendedColor.TYPE_CMYK: if (patternColorspaceCMYK == null) { patternColorspaceCMYK = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); PdfArray array = new PdfArray(PdfName.PATTERN); array.Add(PdfName.DEVICECMYK); AddToBody(array, patternColorspaceCMYK.IndirectReference); } return patternColorspaceCMYK; case ExtendedColor.TYPE_GRAY: if (patternColorspaceGRAY == null) { patternColorspaceGRAY = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); PdfArray array = new PdfArray(PdfName.PATTERN); array.Add(PdfName.DEVICEGRAY); AddToBody(array, patternColorspaceGRAY.IndirectReference); } return patternColorspaceGRAY; case ExtendedColor.TYPE_SEPARATION: { ColorDetails details = AddSimple(((SpotColor)color).PdfSpotColor); ColorDetails patternDetails = (ColorDetails)documentSpotPatterns[details]; if (patternDetails == null) { patternDetails = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); PdfArray array = new PdfArray(PdfName.PATTERN); array.Add(details.IndirectReference); AddToBody(array, patternDetails.IndirectReference); documentSpotPatterns[details] = patternDetails; } return patternDetails; } default: throw new Exception("Invalid color type in PdfWriter.AddSimplePatternColorspace()."); } } // [M3] Images /** Sets the image sequence to follow the text in strict order. * @param strictImageSequence new value of property strictImageSequence * */ public bool StrictImageSequence { set { pdf.StrictImageSequence = value; } get { return pdf.StrictImageSequence; } } /** * Clears text wrapping around images (if applicable). * Method suggested by Pelikan Stephan * @throws DocumentException */ public void ClearTextWrap() { pdf.ClearTextWrap(); } /** Dictionary, containing all the images of the PDF document */ protected PdfDictionary imageDictionary = new PdfDictionary(); /** This is the list with all the images in the document. */ private Hashtable images = new Hashtable(); /** * Adds an image to the document but not to the page resources. It is used with * templates and Document.Add(Image). * @param image the Image to add * @return the name of the image added * @throws PdfException on error * @throws DocumentException on error */ public PdfName AddDirectImageSimple(Image image) { return AddDirectImageSimple(image, null); } /** * Adds an image to the document but not to the page resources. It is used with * templates and Document.Add(Image). * @param image the Image to add * @param fixedRef the reference to used. It may be null, * a PdfIndirectReference or a PRIndirectReference. * @return the name of the image added * @throws PdfException on error * @throws DocumentException on error */ public PdfName AddDirectImageSimple(Image image, PdfIndirectReference fixedRef) { PdfName name; // if the images is already added, just retrieve the name if (images.ContainsKey(image.MySerialId)) { name = (PdfName) images[image.MySerialId]; } // if it's a new image, add it to the document else { if (image.IsImgTemplate()) { name = new PdfName("img" + images.Count); if (image is ImgWMF){ ImgWMF wmf = (ImgWMF)image; wmf.ReadWMF(PdfTemplate.CreateTemplate(this, 0, 0)); } } else { PdfIndirectReference dref = image.DirectReference; if (dref != null) { PdfName rname = new PdfName("img" + images.Count); images[image.MySerialId] = rname; imageDictionary.Put(rname, dref); return rname; } Image maskImage = image.ImageMask; PdfIndirectReference maskRef = null; if (maskImage != null) { PdfName mname = (PdfName)images[maskImage.MySerialId]; maskRef = GetImageReference(mname); } PdfImage i = new PdfImage(image, "img" + images.Count, maskRef); if (image.HasICCProfile()) { PdfICCBased icc = new PdfICCBased(image.TagICC); PdfIndirectReference iccRef = Add(icc); PdfArray iccArray = new PdfArray(); iccArray.Add(PdfName.ICCBASED); iccArray.Add(iccRef); PdfObject colorspace = i.Get(PdfName.COLORSPACE); if (colorspace != null && colorspace.IsArray()) { ArrayList ar = ((PdfArray)colorspace).ArrayList; if (ar.Count > 1 && PdfName.INDEXED.Equals(ar[0])) ar[1] = iccArray; else i.Put(PdfName.COLORSPACE, iccArray); } else i.Put(PdfName.COLORSPACE, iccArray); } Add(i, fixedRef); name = i.Name; } images[image.MySerialId] = name; } return name; } /** * Writes a PdfImage to the outputstream. * * @param pdfImage the image to be added * @return a PdfIndirectReference to the encapsulated image * @throws PdfException when a document isn't open yet, or has been closed */ internal virtual PdfIndirectReference Add(PdfImage pdfImage, PdfIndirectReference fixedRef) { if (! imageDictionary.Contains(pdfImage.Name)) { PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_IMAGE, pdfImage); if (fixedRef is PRIndirectReference) { PRIndirectReference r2 = (PRIndirectReference)fixedRef; fixedRef = new PdfIndirectReference(0, GetNewObjectNumber(r2.Reader, r2.Number, r2.Generation)); } if (fixedRef == null) fixedRef = AddToBody(pdfImage).IndirectReference; else AddToBody(pdfImage, fixedRef); imageDictionary.Put(pdfImage.Name, fixedRef); return fixedRef; } return (PdfIndirectReference)imageDictionary.Get(pdfImage.Name); } /** * return the PdfIndirectReference to the image with a given name. * * @param name the name of the image * @return a PdfIndirectReference */ internal virtual PdfIndirectReference GetImageReference(PdfName name) { return (PdfIndirectReference) imageDictionary.Get(name); } protected virtual PdfIndirectReference Add(PdfICCBased icc) { PdfIndirectObject objecta; objecta = AddToBody(icc); return objecta.IndirectReference; } // [M4] Old table functionality; do we still need it? /** * Checks if a Table fits the current page of the PdfDocument. * * @param table the table that has to be checked * @param margin a certain margin * @return true if the Table fits the page, false otherwise. */ public bool FitsPage(Table table, float margin) { return pdf.GetBottom(table) > pdf.IndentBottom + margin; } /** * Checks if a Table fits the current page of the PdfDocument. * * @param table the table that has to be checked * @return true if the Table fits the page, false otherwise. */ public bool FitsPage(Table table) { return FitsPage(table, 0); } // [F12] tagged PDF /** * A flag indicating the presence of structure elements that contain user properties attributes. */ private bool userProperties; /** * Sets the flag indicating the presence of structure elements that contain user properties attributes. * @param userProperties the user properties flag */ public bool UserProperties { set { userProperties = value; } get { return userProperties; } } /** * Holds value of property RGBTranparency. */ private bool rgbTransparencyBlending; /** * Sets the transparency blending colorspace to RGB. The default blending colorspace is * CMYK and will result in faded colors in the screen and in printing. Calling this method * will return the RGB colors to what is expected. The RGB blending will be applied to all subsequent pages * until other value is set. * Note that this is a generic solution that may not work in all cases. * @param rgbTransparencyBlending true to set the transparency blending colorspace to RGB, false * to use the default blending colorspace */ public bool RgbTransparencyBlending { get { return this.rgbTransparencyBlending; } set { this.rgbTransparencyBlending = value; } } } }