using System; using System.IO; using System.Collections; using System.util; using iTextSharp.text.pdf.interfaces; using iTextSharp.text.pdf.intern; using iTextSharp.text.pdf.collection; /* * Copyright 2003 by Paulo Soares. * * 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 { public class PdfStamperImp : PdfWriter { internal Hashtable readers2intrefs = new Hashtable(); internal Hashtable readers2file = new Hashtable(); internal RandomAccessFileOrArray file; internal PdfReader reader; internal IntHashtable myXref = new IntHashtable(); /** Integer(page number) -> PageStamp */ internal Hashtable pagesToContent = new Hashtable(); internal bool closed = false; /** Holds value of property rotateContents. */ private bool rotateContents = true; protected AcroFields acroFields; protected bool flat = false; protected bool flatFreeText = false; protected int[] namePtr = {0}; protected Hashtable partialFlattening = new Hashtable(); protected bool useVp = false; protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); protected Hashtable fieldTemplates = new Hashtable(); protected bool fieldsAdded = false; protected int sigFlags = 0; protected internal bool append; protected IntHashtable marked; protected int initialXrefSize; protected PdfAction openAction; /** Creates new PdfStamperImp. * @param reader the read PDF * @param os the output destination * @param pdfVersion the new pdf version or '\0' to keep the same version as the original * document * @param append * @throws DocumentException on error * @throws IOException */ internal PdfStamperImp(PdfReader reader, Stream os, char pdfVersion, bool append) : base(new PdfDocument(), os) { if (!reader.IsOpenedWithFullPermissions) throw new ArgumentException("PdfReader not opened with owner password"); if (reader.Tampered) throw new DocumentException("The original document was reused. Read it again from file."); reader.Tampered = true; this.reader = reader; file = reader.SafeFile; this.append = append; if (append) { if (reader.IsRebuilt()) throw new DocumentException("Append mode requires a document without errors even if recovery was possible."); if (reader.IsEncrypted()) crypto = new PdfEncryption(reader.Decrypt); pdf_version.SetAppendmode(true); file.ReOpen(); byte[] buf = new byte[8192]; int n; while ((n = file.Read(buf)) > 0) this.os.Write(buf, 0, n); file.Close(); prevxref = reader.LastXref; reader.Appendable = true; } else { if (pdfVersion == 0) base.PdfVersion = reader.PdfVersion; else base.PdfVersion = pdfVersion; } base.Open(); pdf.AddWriter(this); if (append) { body.Refnum = reader.XrefSize; marked = new IntHashtable(); if (reader.IsNewXrefType()) fullCompression = true; if (reader.IsHybridXref()) fullCompression = false; } initialXrefSize = reader.XrefSize; } internal void Close(Hashtable moreInfo) { if (closed) return; if (useVp) { reader.SetViewerPreferences(viewerPreferences); MarkUsed(reader.Trailer.Get(PdfName.ROOT)); } if (flat) FlatFields(); if (flatFreeText) FlatFreeTextFields(); AddFieldResources(); PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM), reader.Catalog); if (acroFields != null && acroFields.Xfa.Changed) { MarkUsed(acroForm); if (!flat) acroFields.Xfa.SetXfa(this); } if (sigFlags != 0) { if (acroForm != null) { acroForm.Put(PdfName.SIGFLAGS, new PdfNumber(sigFlags)); MarkUsed(acroForm); } } closed = true; AddSharedObjectsToBody(); SetOutlines(); SetJavaScript(); AddFileAttachments(); PdfDictionary catalog = reader.Catalog; if (openAction != null) { catalog.Put(PdfName.OPENACTION, openAction); } if (pdf.pageLabels != null) catalog.Put(PdfName.PAGELABELS, pdf.pageLabels.GetDictionary(this)); byte[] altMetadata = null; PdfObject xmpo = PdfReader.GetPdfObject(catalog.Get(PdfName.METADATA)); if (xmpo != null && xmpo.IsStream()) { altMetadata = PdfReader.GetStreamBytesRaw((PRStream)xmpo); PdfReader.KillIndirect(catalog.Get(PdfName.METADATA)); } if (xmpMetadata != null) { altMetadata = xmpMetadata; } // if there is XMP data to add: add it if (altMetadata != null) { PdfStream xmp = new PdfStream(altMetadata); 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); MarkUsed(catalog); } if (documentOCG.Count != 0) { FillOCProperties(false); PdfDictionary ocdict = catalog.GetAsDict(PdfName.OCPROPERTIES); if (ocdict == null) { reader.Catalog.Put(PdfName.OCPROPERTIES, OCProperties); } else { ocdict.Put(PdfName.OCGS, OCProperties.Get(PdfName.OCGS)); PdfDictionary ddict = ocdict.GetAsDict(PdfName.D); ddict.Put(PdfName.ORDER, OCProperties.GetAsDict(PdfName.D).Get(PdfName.ORDER)); ddict.Put(PdfName.RBGROUPS, OCProperties.GetAsDict(PdfName.D).Get(PdfName.RBGROUPS)); ddict.Put(PdfName.OFF, OCProperties.GetAsDict(PdfName.D).Get(PdfName.OFF)); ddict.Put(PdfName.AS, OCProperties.GetAsDict(PdfName.D).Get(PdfName.AS)); } } PRIndirectReference iInfo = null; try { file.ReOpen(); AlterContents(); iInfo = (PRIndirectReference)reader.trailer.Get(PdfName.INFO); int skip = -1; if (iInfo != null) skip = iInfo.Number; int rootN = ((PRIndirectReference)reader.trailer.Get(PdfName.ROOT)).Number; if (append) { int[] keys = marked.GetKeys(); for (int k = 0; k < keys.Length; ++k) { int j = keys[k]; PdfObject obj = reader.GetPdfObjectRelease(j); if (obj != null && skip != j && j < initialXrefSize) { AddToBody(obj, j, j != rootN); } } for (int k = initialXrefSize; k < reader.XrefSize; ++k) { PdfObject obj = reader.GetPdfObject(k); if (obj != null) { AddToBody(obj, GetNewObjectNumber(reader, k, 0)); } } } else { for (int k = 1; k < reader.XrefSize; ++k) { PdfObject obj = reader.GetPdfObjectRelease(k); if (obj != null && skip != k) { AddToBody(obj, GetNewObjectNumber(reader, k, 0), k != rootN); } } } } finally { try { file.Close(); } catch { // empty on purpose } } PdfIndirectReference encryption = null; PdfObject fileID = null; if (crypto != null) { if (append) { encryption = reader.GetCryptoRef(); } else { PdfIndirectObject encryptionObject = AddToBody(crypto.GetEncryptionDictionary(), false); encryption = encryptionObject.IndirectReference; } fileID = crypto.FileID; } else fileID = PdfEncryption.CreateInfoId(PdfEncryption.CreateDocumentId()); PRIndirectReference iRoot = (PRIndirectReference)reader.trailer.Get(PdfName.ROOT); PdfIndirectReference root = new PdfIndirectReference(0, GetNewObjectNumber(reader, iRoot.Number, 0)); PdfIndirectReference info = null; PdfDictionary oldInfo = (PdfDictionary)PdfReader.GetPdfObject(iInfo); PdfDictionary newInfo = new PdfDictionary(); if (oldInfo != null) { foreach (PdfName key in oldInfo.Keys) { PdfObject value = PdfReader.GetPdfObject(oldInfo.Get(key)); newInfo.Put(key, value); } } if (moreInfo != null) { foreach (DictionaryEntry entry in moreInfo) { PdfName keyName = new PdfName((String)entry.Key); String value = (String)entry.Value; if (value == null) newInfo.Remove(keyName); else newInfo.Put(keyName, new PdfString(value, PdfObject.TEXT_UNICODE)); } } if (altMetadata == null) // hack because changing the modification data makes the XMP data inconsistent newInfo.Put(PdfName.MODDATE, new PdfDate()); if (append) { if (iInfo == null) info = AddToBody(newInfo, false).IndirectReference; else info = AddToBody(newInfo, iInfo.Number, false).IndirectReference; } else { info = AddToBody(newInfo, false).IndirectReference; } // write the cross-reference table of the body body.WriteCrossReferenceTable(os, root, info, encryption, fileID, prevxref); 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, root, info, encryption, fileID, prevxref); trailer.ToPdf(this, os); } os.Flush(); if (CloseStream) os.Close(); reader.Close(); } internal void ApplyRotation(PdfDictionary pageN, ByteBuffer out_p) { if (!rotateContents) return; Rectangle page = reader.GetPageSizeWithRotation(pageN); int rotation = page.Rotation; switch (rotation) { case 90: out_p.Append(PdfContents.ROTATE90); out_p.Append(page.Top); out_p.Append(' ').Append('0').Append(PdfContents.ROTATEFINAL); break; case 180: out_p.Append(PdfContents.ROTATE180); out_p.Append(page.Right); out_p.Append(' '); out_p.Append(page.Top); out_p.Append(PdfContents.ROTATEFINAL); break; case 270: out_p.Append(PdfContents.ROTATE270); out_p.Append('0').Append(' '); out_p.Append(page.Right); out_p.Append(PdfContents.ROTATEFINAL); break; } } internal void AlterContents() { foreach (PageStamp ps in pagesToContent.Values) { PdfDictionary pageN = ps.pageN; MarkUsed(pageN); PdfArray ar = null; PdfObject content = PdfReader.GetPdfObject(pageN.Get(PdfName.CONTENTS), pageN); if (content == null) { ar = new PdfArray(); pageN.Put(PdfName.CONTENTS, ar); } else if (content.IsArray()) { ar = (PdfArray)content; MarkUsed(ar); } else if (content.IsStream()) { ar = new PdfArray(); ar.Add(pageN.Get(PdfName.CONTENTS)); pageN.Put(PdfName.CONTENTS, ar); } else { ar = new PdfArray(); pageN.Put(PdfName.CONTENTS, ar); } ByteBuffer out_p = new ByteBuffer(); if (ps.under != null) { out_p.Append(PdfContents.SAVESTATE); ApplyRotation(pageN, out_p); out_p.Append(ps.under.InternalBuffer); out_p.Append(PdfContents.RESTORESTATE); } if (ps.over != null) out_p.Append(PdfContents.SAVESTATE); PdfStream stream = new PdfStream(out_p.ToByteArray()); stream.FlateCompress(); ar.AddFirst(AddToBody(stream).IndirectReference); out_p.Reset(); if (ps.over != null) { out_p.Append(' '); out_p.Append(PdfContents.RESTORESTATE); ByteBuffer buf = ps.over.InternalBuffer; out_p.Append(buf.Buffer, 0, ps.replacePoint); out_p.Append(PdfContents.SAVESTATE); ApplyRotation(pageN, out_p); out_p.Append(buf.Buffer, ps.replacePoint, buf.Size - ps.replacePoint); out_p.Append(PdfContents.RESTORESTATE); stream = new PdfStream(out_p.ToByteArray()); stream.FlateCompress(); ar.Add(AddToBody(stream).IndirectReference); } AlterResources(ps); } } internal void AlterResources(PageStamp ps) { ps.pageN.Put(PdfName.RESOURCES, ps.pageResources.Resources); } protected internal override int GetNewObjectNumber(PdfReader reader, int number, int generation) { IntHashtable ref_p = (IntHashtable)readers2intrefs[reader]; if (ref_p != null) { int n = ref_p[number]; if (n == 0) { n = IndirectReferenceNumber; ref_p[number] = n; } return n; } if (currentPdfReaderInstance == null) { if (append && number < initialXrefSize) return number; int n = myXref[number]; if (n == 0) { n = IndirectReferenceNumber; myXref[number] = n; } return n; } else return currentPdfReaderInstance.GetNewObjectNumber(number, generation); } internal override RandomAccessFileOrArray GetReaderFile(PdfReader reader) { if (readers2intrefs.ContainsKey(reader)) { RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file[reader]; if (raf != null) return raf; return reader.SafeFile; } if (currentPdfReaderInstance == null) return file; else return currentPdfReaderInstance.ReaderFile; } /** * @param reader * @param openFile * @throws IOException */ public void RegisterReader(PdfReader reader, bool openFile) { if (readers2intrefs.ContainsKey(reader)) return; readers2intrefs[reader] = new IntHashtable(); if (openFile) { RandomAccessFileOrArray raf = reader.SafeFile; readers2file[reader] = raf; raf.ReOpen(); } } /** * @param reader */ public void UnRegisterReader(PdfReader reader) { if (!readers2intrefs.ContainsKey(reader)) return; readers2intrefs.Remove(reader); RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file[reader]; if (raf == null) return; readers2file.Remove(reader); try{raf.Close();}catch{} } internal static void FindAllObjects(PdfReader reader, PdfObject obj, IntHashtable hits) { if (obj == null) return; switch (obj.Type) { case PdfObject.INDIRECT: PRIndirectReference iref = (PRIndirectReference)obj; if (reader != iref.Reader) return; if (hits.ContainsKey(iref.Number)) return; hits[iref.Number] = 1; FindAllObjects(reader, PdfReader.GetPdfObject(obj), hits); return; case PdfObject.ARRAY: ArrayList lst = ((PdfArray)obj).ArrayList; for (int k = 0; k < lst.Count; ++k) { FindAllObjects(reader, (PdfObject)lst[k], hits); } return; case PdfObject.DICTIONARY: case PdfObject.STREAM: PdfDictionary dic = (PdfDictionary)obj; foreach (PdfName name in dic.Keys) { FindAllObjects(reader, dic.Get(name), hits); } return; } } /** * @param fdf * @throws IOException */ public void AddComments(FdfReader fdf) { if (readers2intrefs.ContainsKey(fdf)) return; PdfDictionary catalog = fdf.Catalog; catalog = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.FDF)); if (catalog == null) return; PdfArray annots = (PdfArray)PdfReader.GetPdfObject(catalog.Get(PdfName.ANNOTS)); if (annots == null || annots.Size == 0) return; RegisterReader(fdf, false); IntHashtable hits = new IntHashtable(); Hashtable irt = new Hashtable(); ArrayList an = new ArrayList(); ArrayList ar = annots.ArrayList; for (int k = 0; k < ar.Count; ++k) { PdfObject obj = (PdfObject)ar[k]; PdfDictionary annot = (PdfDictionary)PdfReader.GetPdfObject(obj); PdfNumber page = (PdfNumber)PdfReader.GetPdfObject(annot.Get(PdfName.PAGE)); if (page == null || page.IntValue >= reader.NumberOfPages) continue; FindAllObjects(fdf, obj, hits); an.Add(obj); if (obj.Type == PdfObject.INDIRECT) { PdfObject nm = PdfReader.GetPdfObject(annot.Get(PdfName.NM)); if (nm != null && nm.Type == PdfObject.STRING) irt[nm.ToString()] = obj; } } int[] arhits = hits.GetKeys(); for (int k = 0; k < arhits.Length; ++k) { int n = arhits[k]; PdfObject obj = fdf.GetPdfObject(n); if (obj.Type == PdfObject.DICTIONARY) { PdfObject str = PdfReader.GetPdfObject(((PdfDictionary)obj).Get(PdfName.IRT)); if (str != null && str.Type == PdfObject.STRING) { PdfObject i = (PdfObject)irt[str.ToString()]; if (i != null) { PdfDictionary dic2 = new PdfDictionary(); dic2.Merge((PdfDictionary)obj); dic2.Put(PdfName.IRT, i); obj = dic2; } } } AddToBody(obj, GetNewObjectNumber(fdf, n, 0)); } for (int k = 0; k < an.Count; ++k) { PdfObject obj = (PdfObject)an[k]; PdfDictionary annot = (PdfDictionary)PdfReader.GetPdfObject(obj); PdfNumber page = (PdfNumber)PdfReader.GetPdfObject(annot.Get(PdfName.PAGE)); PdfDictionary dic = reader.GetPageN(page.IntValue + 1); PdfArray annotsp = (PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.ANNOTS), dic); if (annotsp == null) { annotsp = new PdfArray(); dic.Put(PdfName.ANNOTS, annotsp); MarkUsed(dic); } MarkUsed(annotsp); annotsp.Add(obj); } } internal PageStamp GetPageStamp(int pageNum) { PdfDictionary pageN = reader.GetPageN(pageNum); PageStamp ps = (PageStamp)pagesToContent[pageN]; if (ps == null) { ps = new PageStamp(this, reader, pageN); pagesToContent[pageN] = ps; } return ps; } internal PdfContentByte GetUnderContent(int pageNum) { if (pageNum < 1 || pageNum > reader.NumberOfPages) return null; PageStamp ps = GetPageStamp(pageNum); if (ps.under == null) ps.under = new StampContent(this, ps); return ps.under; } internal PdfContentByte GetOverContent(int pageNum) { if (pageNum < 1 || pageNum > reader.NumberOfPages) return null; PageStamp ps = GetPageStamp(pageNum); if (ps.over == null) ps.over = new StampContent(this, ps); return ps.over; } internal void CorrectAcroFieldPages(int page) { if (acroFields == null) return; if (page > reader.NumberOfPages) return; Hashtable fields = acroFields.Fields; foreach (AcroFields.Item item in fields.Values) { ArrayList pages = item.page; for (int k = 0; k < pages.Count; ++k) { int p = (int)pages[k]; if (p >= page) pages[k] = p + 1; } } } private static void MoveRectangle(PdfDictionary dic2, PdfReader r, int pageImported, PdfName key, String name) { Rectangle m = r.GetBoxSize(pageImported, name); if (m == null) dic2.Remove(key); else dic2.Put(key, new PdfRectangle(m)); } internal void ReplacePage(PdfReader r, int pageImported, int pageReplaced) { PdfDictionary pageN = reader.GetPageN(pageReplaced); if (pagesToContent.ContainsKey(pageN)) throw new InvalidOperationException("This page cannot be replaced: new content was already added"); PdfImportedPage p = GetImportedPage(r, pageImported); PdfDictionary dic2 = reader.GetPageNRelease(pageReplaced); dic2.Remove(PdfName.RESOURCES); dic2.Remove(PdfName.CONTENTS); MoveRectangle(dic2, r, pageImported, PdfName.MEDIABOX, "media"); MoveRectangle(dic2, r, pageImported, PdfName.CROPBOX, "crop"); MoveRectangle(dic2, r, pageImported, PdfName.TRIMBOX, "trim"); MoveRectangle(dic2, r, pageImported, PdfName.ARTBOX, "art"); MoveRectangle(dic2, r, pageImported, PdfName.BLEEDBOX, "bleed"); dic2.Put(PdfName.ROTATE, new PdfNumber(r.GetPageRotation(pageImported))); PdfContentByte cb = GetOverContent(pageReplaced); cb.AddTemplate(p, 0, 0); PageStamp ps = (PageStamp)pagesToContent[pageN]; ps.replacePoint = ps.over.InternalBuffer.Size; } internal void InsertPage(int pageNumber, Rectangle mediabox) { Rectangle media = new Rectangle(mediabox); int rotation = media.Rotation % 360; PdfDictionary page = new PdfDictionary(PdfName.PAGE); PdfDictionary resources = new PdfDictionary(); PdfArray procset = new PdfArray(); procset.Add(PdfName.PDF); procset.Add(PdfName.TEXT); procset.Add(PdfName.IMAGEB); procset.Add(PdfName.IMAGEC); procset.Add(PdfName.IMAGEI); resources.Put(PdfName.PROCSET, procset); page.Put(PdfName.RESOURCES, resources); page.Put(PdfName.ROTATE, new PdfNumber(rotation)); page.Put(PdfName.MEDIABOX, new PdfRectangle(media, rotation)); PRIndirectReference pref = reader.AddPdfObject(page); PdfDictionary parent; PRIndirectReference parentRef; if (pageNumber > reader.NumberOfPages) { PdfDictionary lastPage = reader.GetPageNRelease(reader.NumberOfPages); parentRef = (PRIndirectReference)lastPage.Get(PdfName.PARENT); parentRef = new PRIndirectReference(reader, parentRef.Number); parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS), parent); kids.Add(pref); MarkUsed(kids); reader.pageRefs.InsertPage(pageNumber, pref); } else { if (pageNumber < 1) pageNumber = 1; PdfDictionary firstPage = reader.GetPageN(pageNumber); PRIndirectReference firstPageRef = reader.GetPageOrigRef(pageNumber); reader.ReleasePage(pageNumber); parentRef = (PRIndirectReference)firstPage.Get(PdfName.PARENT); parentRef = new PRIndirectReference(reader, parentRef.Number); parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS), parent); ArrayList ar = kids.ArrayList; int len = ar.Count; int num = firstPageRef.Number; for (int k = 0; k < len; ++k) { PRIndirectReference cur = (PRIndirectReference)ar[k]; if (num == cur.Number) { ar.Insert(k, pref); break; } } if (len == ar.Count) throw new Exception("Internal inconsistence."); MarkUsed(kids); reader.pageRefs.InsertPage(pageNumber, pref); CorrectAcroFieldPages(pageNumber); } page.Put(PdfName.PARENT, parentRef); while (parent != null) { MarkUsed(parent); PdfNumber count = (PdfNumber)PdfReader.GetPdfObjectRelease(parent.Get(PdfName.COUNT)); parent.Put(PdfName.COUNT, new PdfNumber(count.IntValue + 1)); parent = (PdfDictionary)PdfReader.GetPdfObject(parent.Get(PdfName.PARENT)); } } internal bool RotateContents { set { this.rotateContents = value; } get { return rotateContents; } } internal bool ContentWritten { get { return body.Size > 1; } } internal AcroFields AcroFields { get { if (acroFields == null) { acroFields = new AcroFields(reader, this); } return acroFields; } } internal bool FormFlattening { set { flat = value; } } internal bool FreeTextFlattening { set { flatFreeText = value; } } internal bool PartialFormFlattening(String name) { AcroFields af = AcroFields; if (acroFields.Xfa.XfaPresent) throw new InvalidOperationException("Partial form flattening is not supported with XFA forms."); if (!acroFields.Fields.ContainsKey(name)) return false; partialFlattening[name] = null; return true; } internal void FlatFields() { if (append) throw new ArgumentException("Field flattening is not supported in append mode."); AcroFields af = AcroFields; Hashtable fields = acroFields.Fields; if (fieldsAdded && partialFlattening.Count == 0) { foreach (object obf in fields.Keys) { partialFlattening[obf] = null; } } PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); ArrayList acroFds = null; if (acroForm != null) { PdfArray array = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); if (array != null) acroFds = array.ArrayList; } foreach (DictionaryEntry entry in fields) { String name = (String)entry.Key; if (partialFlattening.Count != 0 && !partialFlattening.ContainsKey(name)) continue; AcroFields.Item item = (AcroFields.Item)entry.Value; for (int k = 0; k < item.merged.Count; ++k) { PdfDictionary merged = (PdfDictionary)item.merged[k]; PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.F)); int flags = 0; if (ff != null) flags = ff.IntValue; int page = (int)item.page[k]; PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.AP)); if (appDic != null && (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { PdfObject obj = appDic.Get(PdfName.N); PdfAppearance app = null; if (obj != null) { PdfObject objReal = PdfReader.GetPdfObject(obj); if (obj is PdfIndirectReference && !obj.IsIndirect()) app = new PdfAppearance((PdfIndirectReference)obj); else if (objReal is PdfStream) { ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); app = new PdfAppearance((PdfIndirectReference)obj); } else { if (objReal != null && objReal.IsDictionary()) { PdfName as_p = (PdfName)PdfReader.GetPdfObject(merged.Get(PdfName.AS)); if (as_p != null) { PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).Get(as_p); if (iref != null) { app = new PdfAppearance(iref); if (iref.IsIndirect()) { objReal = PdfReader.GetPdfObject(iref); ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); } } } } } } if (app != null) { Rectangle box = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT))); PdfContentByte cb = GetOverContent(page); cb.SetLiteral("Q "); cb.AddTemplate(app, box.Left, box.Bottom); cb.SetLiteral("q "); } } if (partialFlattening.Count == 0) continue; PdfDictionary pageDic = reader.GetPageN(page); PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); if (annots == null) continue; ArrayList ar = annots.ArrayList; for (int idx = 0; idx < ar.Count; ++idx) { PdfObject ran = (PdfObject)ar[idx]; if (!ran.IsIndirect()) continue; PdfObject ran2 = (PdfObject)item.widget_refs[k]; if (!ran2.IsIndirect()) continue; if (((PRIndirectReference)ran).Number == ((PRIndirectReference)ran2).Number) { ar.RemoveAt(idx--); PRIndirectReference wdref = (PRIndirectReference)ran2; while (true) { PdfDictionary wd = (PdfDictionary)PdfReader.GetPdfObject(wdref); PRIndirectReference parentRef = (PRIndirectReference)wd.Get(PdfName.PARENT); PdfReader.KillIndirect(wdref); if (parentRef == null) { // reached AcroForm for (int fr = 0; fr < acroFds.Count; ++fr) { PdfObject h = (PdfObject)acroFds[fr]; if (h.IsIndirect() && ((PRIndirectReference)h).Number == wdref.Number) { acroFds.RemoveAt(fr); --fr; } } break; } PdfDictionary parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS)); ArrayList kar = kids.ArrayList; for (int fr = 0; fr < kar.Count; ++fr) { PdfObject h = (PdfObject)kar[fr]; if (h.IsIndirect() && ((PRIndirectReference)h).Number == wdref.Number) { kar.RemoveAt(fr); --fr; } } if (kar.Count != 0) break; wdref = parentRef; } } } if (ar.Count == 0) { PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); pageDic.Remove(PdfName.ANNOTS); } } } if (!fieldsAdded && partialFlattening.Count == 0) { for (int page = 1; page <= reader.NumberOfPages; ++page) { PdfDictionary pageDic = reader.GetPageN(page); PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); if (annots == null) continue; ArrayList ar = annots.ArrayList; for (int idx = 0; idx < ar.Count; ++idx) { PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); if ((annoto is PdfIndirectReference) && !annoto.IsIndirect()) continue; if (!annoto.IsDictionary() || PdfName.WIDGET.Equals(((PdfDictionary)annoto).Get(PdfName.SUBTYPE))) { ar.RemoveAt(idx); --idx; } } if (ar.Count == 0) { PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); pageDic.Remove(PdfName.ANNOTS); } } EliminateAcroformObjects(); } } internal void EliminateAcroformObjects() { PdfObject acro = reader.Catalog.Get(PdfName.ACROFORM); if (acro == null) return; PdfDictionary acrodic = (PdfDictionary)PdfReader.GetPdfObject(acro); reader.KillXref(acrodic.Get(PdfName.XFA)); acrodic.Remove(PdfName.XFA); PdfObject iFields = acrodic.Get(PdfName.FIELDS); if (iFields != null) { PdfDictionary kids = new PdfDictionary(); kids.Put(PdfName.KIDS, iFields); SweepKids(kids); PdfReader.KillIndirect(iFields); acrodic.Put(PdfName.FIELDS, new PdfArray()); } // PdfReader.KillIndirect(acro); // reader.GetCatalog().Remove(PdfName.ACROFORM); } internal void SweepKids(PdfObject obj) { PdfObject oo = PdfReader.KillIndirect(obj); if (oo == null || !oo.IsDictionary()) return; PdfDictionary dic = (PdfDictionary)oo; PdfArray kids = (PdfArray)PdfReader.KillIndirect(dic.Get(PdfName.KIDS)); if (kids == null) return; ArrayList ar = kids.ArrayList; for (int k = 0; k < ar.Count; ++k) { SweepKids((PdfObject)ar[k]); } } private void FlatFreeTextFields() { if (append) throw new ArgumentException("FreeText flattening is not supported in append mode."); for (int page = 1; page <= reader.NumberOfPages; ++page) { PdfDictionary pageDic = reader.GetPageN(page); PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); if (annots == null) continue; ArrayList ar = annots.ArrayList; for (int idx = 0; idx < ar.Count; ++idx) { PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); if ((annoto is PdfIndirectReference) && !annoto.IsIndirect()) continue; PdfDictionary annDic = (PdfDictionary)annoto; if (!((PdfName)annDic.Get(PdfName.SUBTYPE)).Equals(PdfName.FREETEXT)) continue; PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(annDic.Get(PdfName.F)); int flags = (ff != null) ? ff.IntValue : 0; if ( (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { PdfObject obj1 = annDic.Get(PdfName.AP); if (obj1 == null) continue; PdfDictionary appDic = (obj1 is PdfIndirectReference) ? (PdfDictionary) PdfReader.GetPdfObject(obj1) : (PdfDictionary) obj1; PdfObject obj = appDic.Get(PdfName.N); PdfAppearance app = null; if (obj != null) { PdfObject objReal = PdfReader.GetPdfObject(obj); if (obj is PdfIndirectReference && !obj.IsIndirect()) app = new PdfAppearance((PdfIndirectReference)obj); else if (objReal is PdfStream) { ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); app = new PdfAppearance((PdfIndirectReference)obj); } else { if (objReal.IsDictionary()) { PdfName as_p = (PdfName)PdfReader.GetPdfObject(appDic.Get(PdfName.AS)); if (as_p != null) { PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).Get(as_p); if (iref != null) { app = new PdfAppearance(iref); if (iref.IsIndirect()) { objReal = PdfReader.GetPdfObject(iref); ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); } } } } } } if (app != null) { Rectangle box = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(annDic.Get(PdfName.RECT))); PdfContentByte cb = this.GetOverContent(page); cb.SetLiteral("Q "); cb.AddTemplate(app, box.Left, box.Bottom); cb.SetLiteral("q "); } } } for (int idx = 0; idx < ar.Count; ++idx) { PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); if (annoto != null && annoto.IsDictionary()) { PdfDictionary annot = (PdfDictionary)annoto; if (PdfName.FREETEXT.Equals(annot.Get(PdfName.SUBTYPE))) { ar.RemoveAt(idx); --idx; } } } if (ar.Count == 0) { PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); pageDic.Remove(PdfName.ANNOTS); } } } /** * @see com.lowagie.text.pdf.PdfWriter#getPageReference(int) */ public override PdfIndirectReference GetPageReference(int page) { PdfIndirectReference ref_p = reader.GetPageOrigRef(page); if (ref_p == null) throw new ArgumentException("Invalid page number " + page); return ref_p; } /** * @see com.lowagie.text.pdf.PdfWriter#addAnnotation(com.lowagie.text.pdf.PdfAnnotation) */ public override void AddAnnotation(PdfAnnotation annot) { throw new Exception("Unsupported in this context. Use PdfStamper.AddAnnotation()"); } internal void AddDocumentField(PdfIndirectReference ref_p) { PdfDictionary catalog = reader.Catalog; PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); if (acroForm == null) { acroForm = new PdfDictionary(); catalog.Put(PdfName.ACROFORM, acroForm); MarkUsed(catalog); } PdfArray fields = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); if (fields == null) { fields = new PdfArray(); acroForm.Put(PdfName.FIELDS, fields); MarkUsed(acroForm); } if (!acroForm.Contains(PdfName.DA)) { acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); MarkUsed(acroForm); } fields.Add(ref_p); MarkUsed(fields); } internal void AddFieldResources() { if (fieldTemplates.Count == 0) return; PdfDictionary catalog = reader.Catalog; PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); if (acroForm == null) { acroForm = new PdfDictionary(); catalog.Put(PdfName.ACROFORM, acroForm); MarkUsed(catalog); } PdfDictionary dr = (PdfDictionary)PdfReader.GetPdfObject(acroForm.Get(PdfName.DR), acroForm); if (dr == null) { dr = new PdfDictionary(); acroForm.Put(PdfName.DR, dr); MarkUsed(acroForm); } MarkUsed(dr); foreach (PdfTemplate template in fieldTemplates.Keys) { PdfFormField.MergeResources(dr, (PdfDictionary)template.Resources, this); } if (dr.Get(PdfName.ENCODING) == null) dr.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); if (fonts == null) { fonts = new PdfDictionary(); dr.Put(PdfName.FONT, fonts); } if (!fonts.Contains(PdfName.HELV)) { PdfDictionary dic = new PdfDictionary(PdfName.FONT); dic.Put(PdfName.BASEFONT, PdfName.HELVETICA); dic.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); dic.Put(PdfName.NAME, PdfName.HELV); dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); fonts.Put(PdfName.HELV, AddToBody(dic).IndirectReference); } if (!fonts.Contains(PdfName.ZADB)) { PdfDictionary dic = new PdfDictionary(PdfName.FONT); dic.Put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS); dic.Put(PdfName.NAME, PdfName.ZADB); dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); fonts.Put(PdfName.ZADB, AddToBody(dic).IndirectReference); } if (acroForm.Get(PdfName.DA) == null) { acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); MarkUsed(acroForm); } } internal void ExpandFields(PdfFormField field, ArrayList allAnnots) { allAnnots.Add(field); ArrayList kids = field.Kids; if (kids != null) { for (int k = 0; k < kids.Count; ++k) { ExpandFields((PdfFormField)kids[k], allAnnots); } } } internal void AddAnnotation(PdfAnnotation annot, PdfDictionary pageN) { ArrayList allAnnots = new ArrayList(); if (annot.IsForm()) { fieldsAdded = true; AcroFields afdummy = AcroFields; PdfFormField field = (PdfFormField)annot; if (field.Parent != null) return; ExpandFields(field, allAnnots); } else allAnnots.Add(annot); for (int k = 0; k < allAnnots.Count; ++k) { annot = (PdfAnnotation)allAnnots[k]; if (annot.PlaceInPage > 0) pageN = reader.GetPageN(annot.PlaceInPage); if (annot.IsForm()) { if (!annot.IsUsed()) { Hashtable templates = annot.Templates; if (templates != null) { foreach (object tpl in templates.Keys) { fieldTemplates[tpl] = null; } } } PdfFormField field = (PdfFormField)annot; if (field.Parent == null) AddDocumentField(field.IndirectReference); } if (annot.IsAnnotation()) { PdfObject pdfobj = PdfReader.GetPdfObject(pageN.Get(PdfName.ANNOTS), pageN); PdfArray annots = null; if (pdfobj == null || !pdfobj.IsArray()) { annots = new PdfArray(); pageN.Put(PdfName.ANNOTS, annots); MarkUsed(pageN); } else annots = (PdfArray)pdfobj; annots.Add(annot.IndirectReference); MarkUsed(annots); if (!annot.IsUsed()) { PdfRectangle rect = (PdfRectangle)annot.Get(PdfName.RECT); if (rect != null && (rect.Left != 0 || rect.Right != 0 || rect.Top != 0 || rect.Bottom != 0)) { int rotation = reader.GetPageRotation(pageN); Rectangle pageSize = reader.GetPageSizeWithRotation(pageN); switch (rotation) { case 90: annot.Put(PdfName.RECT, new PdfRectangle( pageSize.Top - rect.Bottom, rect.Left, pageSize.Top - rect.Top, rect.Right)); break; case 180: annot.Put(PdfName.RECT, new PdfRectangle( pageSize.Right - rect.Left, pageSize.Top - rect.Bottom, pageSize.Right - rect.Right, pageSize.Top - rect.Top)); break; case 270: annot.Put(PdfName.RECT, new PdfRectangle( rect.Bottom, pageSize.Right - rect.Left, rect.Top, pageSize.Right - rect.Right)); break; } } } } if (!annot.IsUsed()) { annot.SetUsed(); AddToBody(annot, annot.IndirectReference); } } } internal override void AddAnnotation(PdfAnnotation annot, int page) { AddAnnotation(annot, reader.GetPageN(page)); } private void OutlineTravel(PRIndirectReference outline) { while (outline != null) { PdfDictionary outlineR = (PdfDictionary)PdfReader.GetPdfObjectRelease(outline); PRIndirectReference first = (PRIndirectReference)outlineR.Get(PdfName.FIRST); if (first != null) { OutlineTravel(first); } PdfReader.KillIndirect(outlineR.Get(PdfName.DEST)); PdfReader.KillIndirect(outlineR.Get(PdfName.A)); PdfReader.KillIndirect(outline); outline = (PRIndirectReference)outlineR.Get(PdfName.NEXT); } } internal void DeleteOutlines() { PdfDictionary catalog = reader.Catalog; PRIndirectReference outlines = (PRIndirectReference)catalog.Get(PdfName.OUTLINES); if (outlines == null) return; OutlineTravel(outlines); PdfReader.KillIndirect(outlines); catalog.Remove(PdfName.OUTLINES); MarkUsed(catalog); } internal void SetJavaScript() { Hashtable djs = pdf.GetDocumentLevelJS(); if (djs.Count == 0) return; PdfDictionary catalog = reader.Catalog; PdfDictionary names = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES), catalog); if (names == null) { names = new PdfDictionary(); catalog.Put(PdfName.NAMES, names); MarkUsed(catalog); } MarkUsed(names); PdfDictionary tree = PdfNameTree.WriteTree(djs, this); names.Put(PdfName.JAVASCRIPT, AddToBody(tree).IndirectReference); } void AddFileAttachments() { Hashtable fs = pdf.GetDocumentFileAttachment(); if (fs.Count == 0) return; PdfDictionary catalog = reader.Catalog; PdfDictionary names = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES), catalog); if (names == null) { names = new PdfDictionary(); catalog.Put(PdfName.NAMES, names); MarkUsed(catalog); } MarkUsed(names); Hashtable old = PdfNameTree.ReadTree((PdfDictionary)PdfReader.GetPdfObjectRelease(names.Get(PdfName.EMBEDDEDFILES))); foreach (DictionaryEntry entry in fs) { String name = (String)entry.Key; int k = 0; String nn = name; while (old.ContainsKey(nn)) { ++k; nn += " " + k; } old[nn] = entry.Value; } PdfDictionary tree = PdfNameTree.WriteTree(old, this); names.Put(PdfName.EMBEDDEDFILES, AddToBody(tree).IndirectReference); } /** * Adds or replaces the Collection Dictionary in the Catalog. * @param collection the new collection dictionary. */ internal void MakePackage(PdfCollection collection) { PdfDictionary catalog = reader.Catalog; catalog.Put( PdfName.COLLECTION, collection ); } internal void SetOutlines() { if (newBookmarks == null) return; DeleteOutlines(); if (newBookmarks.Count == 0) return; PdfDictionary catalog = reader.Catalog; bool namedAsNames = (catalog.Get(PdfName.DESTS) != null); WriteOutlines(catalog, namedAsNames); MarkUsed(catalog); } /** * Sets the viewer preferences. * @param preferences the viewer preferences * @see PdfWriter#setViewerPreferences(int) */ public override int ViewerPreferences { set { useVp = true; this.viewerPreferences.ViewerPreferences = value; } } /** Adds a viewer preference * @param preferences the viewer preferences * @see PdfViewerPreferences#addViewerPreference */ public override void AddViewerPreference(PdfName key, PdfObject value) { useVp = true; this.viewerPreferences.AddViewerPreference(key, value); } /** * Set the signature flags. * @param f the flags. This flags are ORed with current ones */ public override int SigFlags { set { sigFlags |= value; } } /** Always throws an UnsupportedOperationException. * @param actionType ignore * @param action ignore * @throws PdfException ignore * @see PdfStamper#setPageAction(PdfName, PdfAction, int) */ public override void SetPageAction(PdfName actionType, PdfAction action) { throw new InvalidOperationException("Use SetPageAction(PdfName actionType, PdfAction action, int page)"); } /** * 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 * @param page the page where the action will be applied. The first page is 1 * @throws PdfException if the action type is invalid */ internal void SetPageAction(PdfName actionType, PdfAction action, int page) { if (!actionType.Equals(PAGE_OPEN) && !actionType.Equals(PAGE_CLOSE)) throw new PdfException("Invalid page additional action type: " + actionType.ToString()); PdfDictionary pg = reader.GetPageN(page); PdfDictionary aa = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.AA), pg); if (aa == null) { aa = new PdfDictionary(); pg.Put(PdfName.AA, aa); MarkUsed(pg); } aa.Put(actionType, action); MarkUsed(aa); } /** * Always throws an UnsupportedOperationException. * @param seconds ignore */ public override int Duration { set { throw new InvalidOperationException("Use the methods at Pdfstamper."); } } /** * Always throws an UnsupportedOperationException. * @param transition ignore */ public override PdfTransition Transition { set { throw new InvalidOperationException("Use the methods at Pdfstamper."); } } /** * Sets the display duration for the page (for presentations) * @param seconds the number of seconds to display the page. A negative value removes the entry * @param page the page where the duration will be applied. The first page is 1 */ internal void SetDuration(int seconds, int page) { PdfDictionary pg = reader.GetPageN(page); if (seconds < 0) pg.Remove(PdfName.DUR); else pg.Put(PdfName.DUR, new PdfNumber(seconds)); MarkUsed(pg); } /** * Sets the transition for the page * @param transition the transition object. A null removes the transition * @param page the page where the transition will be applied. The first page is 1 */ internal void SetTransition(PdfTransition transition, int page) { PdfDictionary pg = reader.GetPageN(page); if (transition == null) pg.Remove(PdfName.TRANS); else pg.Put(PdfName.TRANS, transition.TransitionDictionary); MarkUsed(pg); } protected internal void MarkUsed(PdfObject obj) { if (append && obj != null) { PRIndirectReference ref_p = null; if (obj.Type == PdfObject.INDIRECT) ref_p = (PRIndirectReference)obj; else ref_p = obj.IndRef; if (ref_p != null) marked[ref_p.Number] = 1; } } protected internal void MarkUsed(int num) { if (append) marked[num] = 1; } /** * Getter for property append. * @return Value of property append. */ internal bool IsAppend() { return append; } /** 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 override 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()); } PdfDictionary aa = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.AA)); if (aa == null) { if (action == null) return; aa = new PdfDictionary(); reader.Catalog.Put(PdfName.AA, aa); } MarkUsed(aa); if (action == null) aa.Remove(actionType); else aa.Put(actionType, action); } /** * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(com.lowagie.text.pdf.PdfAction) */ public override void SetOpenAction(PdfAction action) { openAction = action; } /** * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(java.lang.String) */ public override void SetOpenAction(String name) { throw new InvalidOperationException("Open actions by name are not supported."); } /** * @see com.lowagie.text.pdf.PdfWriter#setThumbnail(com.lowagie.text.Image) */ public override Image Thumbnail { set { throw new InvalidOperationException("Use PdfStamper.Thumbnail"); } } internal void SetThumbnail(Image image, int page) { PdfIndirectReference thumb = GetImageReference(AddDirectImageSimple(image)); reader.ResetReleasePage(); PdfDictionary dic = reader.GetPageN(page); dic.Put(PdfName.THUMB, thumb); reader.ResetReleasePage(); } /** * Reads the OCProperties dictionary from the catalog of the existing document * and fills the documentOCG, documentOCGorder and OCGRadioGroup variables in PdfWriter. * Note that the original OCProperties of the existing document can contain more information. * @since 2.1.2 */ protected void ReadOCProperties() { if (documentOCG.Count != 0) { return; } PdfDictionary dict = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES); if (dict == null) { return; } PdfArray ocgs = dict.GetAsArray(PdfName.OCGS); PdfIndirectReference refi; PdfLayer layer; Hashtable ocgmap = new Hashtable(); for (ListIterator i = ocgs.GetListIterator(); i.HasNext();) { refi = (PdfIndirectReference)i.Next(); layer = new PdfLayer(null); layer.Ref = refi; layer.OnPanel = false; layer.Merge((PdfDictionary)PdfReader.GetPdfObject(refi)); ocgmap[refi.ToString()] = layer; } PdfDictionary d = dict.GetAsDict(PdfName.D); PdfArray off = d.GetAsArray(PdfName.OFF); if (off != null) { for (ListIterator i = off.GetListIterator(); i.HasNext(); ) { refi = (PdfIndirectReference)i.Next(); layer = (PdfLayer)ocgmap[refi.ToString()]; layer.On = false; } } PdfArray order = d.GetAsArray(PdfName.ORDER); if (order != null) { AddOrder(null, order, ocgmap); } foreach (object o in ocgmap.Values) documentOCG[o] = null; OCGRadioGroup = d.GetAsArray(PdfName.RBGROUPS); OCGLocked = d.GetAsArray(PdfName.LOCKED); } /** * Recursive method to reconstruct the documentOCGorder variable in the writer. * @param parent a parent PdfLayer (can be null) * @param arr an array possibly containing children for the parent PdfLayer * @param ocgmap a Hashtable with indirect reference Strings as keys and PdfLayer objects as values. * @since 2.1.2 */ private void AddOrder(PdfLayer parent, PdfArray arr, Hashtable ocgmap) { PdfObject obj; PdfLayer layer; for (int i = 0; i < arr.Size; i++) { obj = arr.GetPdfObject(i); if (obj.IsIndirect()) { layer = (PdfLayer)ocgmap[obj.ToString()]; layer.OnPanel = true; RegisterLayer(layer); if (parent != null) { parent.AddChild(layer); } if (arr.Size > i + 1 && arr.GetPdfObject(i + 1).IsArray()) { i++; AddOrder(layer, (PdfArray)arr.GetPdfObject(i), ocgmap); } } else if (obj.IsArray()) { ArrayList sub = ((PdfArray)obj).ArrayList; if (sub.Count == 0) return; obj = (PdfObject)sub[0]; if (obj.IsString()) { layer = new PdfLayer(sub[0].ToString()); layer.OnPanel = true; RegisterLayer(layer); if (parent != null) { parent.AddChild(layer); } PdfArray array = new PdfArray(); foreach (PdfObject o2 in sub) { array.Add(o2); } AddOrder(layer, array, ocgmap); } else { AddOrder(parent, (PdfArray)obj, ocgmap); } } } } /** * Gets the PdfLayer objects in an existing document as a Map * with the names/titles of the layers as keys. * @return a Map with all the PdfLayers in the document (and the name/title of the layer as key) * @since 2.1.2 */ public Hashtable GetPdfLayers() { if (documentOCG.Count == 0) { ReadOCProperties(); } Hashtable map = new Hashtable(); String key; foreach (PdfLayer layer in documentOCG) { if (layer.Title == null) { key = layer.GetAsString(PdfName.NAME).ToString(); } else { key = layer.Title; } if (map.ContainsKey(key)) { int seq = 2; String tmp = key + "(" + seq + ")"; while (map.ContainsKey(tmp)) { seq++; tmp = key + "(" + seq + ")"; } key = tmp; } map[key] = layer; } return map; } internal class PageStamp { internal PdfDictionary pageN; internal StampContent under; internal StampContent over; internal PageResources pageResources; internal int replacePoint = 0; internal PageStamp(PdfStamperImp stamper, PdfReader reader, PdfDictionary pageN) { this.pageN = pageN; pageResources = new PageResources(); PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); pageResources.SetOriginalResources(resources, stamper.namePtr); } } public override PdfContentByte DirectContent { get { throw new InvalidOperationException("Use PdfStamper.GetUnderContent() or PdfStamper.GetOverContent()"); } } public override PdfContentByte DirectContentUnder { get { throw new InvalidOperationException("Use PdfStamper.GetUnderContent() or PdfStamper.GetOverContent()"); } } } }