0001: /*
0002: * Copyright 2003 by Paulo Soares.
0003: *
0004: * The contents of this file are subject to the Mozilla Public License Version 1.1
0005: * (the "License"); you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0007: *
0008: * Software distributed under the License is distributed on an "AS IS" basis,
0009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0010: * for the specific language governing rights and limitations under the License.
0011: *
0012: * The Original Code is 'iText, a free JAVA-PDF library'.
0013: *
0014: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0015: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0016: * All Rights Reserved.
0017: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0018: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0019: *
0020: * Contributor(s): all the names of the contributors are added in the source code
0021: * where applicable.
0022: *
0023: * Alternatively, the contents of this file may be used under the terms of the
0024: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0025: * provisions of LGPL are applicable instead of those above. If you wish to
0026: * allow use of your version of this file only under the terms of the LGPL
0027: * License and not to allow others to use your version of this file under
0028: * the MPL, indicate your decision by deleting the provisions above and
0029: * replace them with the notice and other provisions required by the LGPL.
0030: * If you do not delete the provisions above, a recipient may use your version
0031: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0032: *
0033: * This library is free software; you can redistribute it and/or modify it
0034: * under the terms of the MPL as stated above or under the terms of the GNU
0035: * Library General Public License as published by the Free Software Foundation;
0036: * either version 2 of the License, or any later version.
0037: *
0038: * This library is distributed in the hope that it will be useful, but WITHOUT
0039: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0040: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0041: * details.
0042: *
0043: * If you didn't download this code from the following link, you should check if
0044: * you aren't using an obsolete version:
0045: * http://www.lowagie.com/iText/
0046: */
0047: package com.lowagie.text.pdf;
0048:
0049: import java.io.IOException;
0050: import java.io.OutputStream;
0051: import java.util.ArrayList;
0052: import java.util.HashMap;
0053: import java.util.HashSet;
0054: import java.util.Iterator;
0055: import java.util.Map;
0056:
0057: import com.lowagie.text.DocumentException;
0058: import com.lowagie.text.ExceptionConverter;
0059: import com.lowagie.text.Image;
0060: import com.lowagie.text.Rectangle;
0061: import com.lowagie.text.pdf.collection.PdfCollection;
0062: import com.lowagie.text.pdf.interfaces.PdfViewerPreferences;
0063: import com.lowagie.text.pdf.internal.PdfViewerPreferencesImp;
0064:
0065: class PdfStamperImp extends PdfWriter {
0066: HashMap readers2intrefs = new HashMap();
0067: HashMap readers2file = new HashMap();
0068: RandomAccessFileOrArray file;
0069: PdfReader reader;
0070: IntHashtable myXref = new IntHashtable();
0071: /** Integer(page number) -> PageStamp */
0072: HashMap pagesToContent = new HashMap();
0073: boolean closed = false;
0074: /** Holds value of property rotateContents. */
0075: private boolean rotateContents = true;
0076: protected AcroFields acroFields;
0077: protected boolean flat = false;
0078: protected boolean flatFreeText = false;
0079: protected int namePtr[] = { 0 };
0080: protected HashSet partialFlattening = new HashSet();
0081: protected boolean useVp = false;
0082: protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp();
0083: protected HashMap fieldTemplates = new HashMap();
0084: protected boolean fieldsAdded = false;
0085: protected int sigFlags = 0;
0086: protected boolean append;
0087: protected IntHashtable marked;
0088: protected int initialXrefSize;
0089: protected PdfAction openAction;
0090:
0091: /** Creates new PdfStamperImp.
0092: * @param reader the read PDF
0093: * @param os the output destination
0094: * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
0095: * document
0096: * @param append
0097: * @throws DocumentException on error
0098: * @throws IOException
0099: */
0100: PdfStamperImp(PdfReader reader, OutputStream os, char pdfVersion,
0101: boolean append) throws DocumentException, IOException {
0102: super (new PdfDocument(), os);
0103: if (!reader.isOpenedWithFullPermissions())
0104: throw new IllegalArgumentException(
0105: "PdfReader not opened with owner password");
0106: if (reader.isTampered())
0107: throw new DocumentException(
0108: "The original document was reused. Read it again from file.");
0109: reader.setTampered(true);
0110: this .reader = reader;
0111: file = reader.getSafeFile();
0112: this .append = append;
0113: if (append) {
0114: if (reader.isRebuilt())
0115: throw new DocumentException(
0116: "Append mode requires a document without errors even if recovery was possible.");
0117: if (reader.isEncrypted())
0118: crypto = new PdfEncryption(reader.getDecrypt());
0119: pdf_version.setAppendmode(true);
0120: file.reOpen();
0121: byte buf[] = new byte[8192];
0122: int n;
0123: while ((n = file.read(buf)) > 0)
0124: this .os.write(buf, 0, n);
0125: file.close();
0126: prevxref = reader.getLastXref();
0127: reader.setAppendable(true);
0128: } else {
0129: if (pdfVersion == 0)
0130: super .setPdfVersion(reader.getPdfVersion());
0131: else
0132: super .setPdfVersion(pdfVersion);
0133: }
0134: super .open();
0135: pdf.addWriter(this );
0136: if (append) {
0137: body.setRefnum(reader.getXrefSize());
0138: marked = new IntHashtable();
0139: if (reader.isNewXrefType())
0140: fullCompression = true;
0141: if (reader.isHybridXref())
0142: fullCompression = false;
0143: }
0144: initialXrefSize = reader.getXrefSize();
0145: }
0146:
0147: void close(HashMap moreInfo) throws IOException {
0148: if (closed)
0149: return;
0150: if (useVp) {
0151: reader.setViewerPreferences(viewerPreferences);
0152: markUsed(reader.getTrailer().get(PdfName.ROOT));
0153: }
0154: if (flat)
0155: flatFields();
0156: if (flatFreeText)
0157: flatFreeTextFields();
0158: addFieldResources();
0159: PdfDictionary acroForm = (PdfDictionary) PdfReader
0160: .getPdfObject(
0161: reader.getCatalog().get(PdfName.ACROFORM),
0162: reader.getCatalog());
0163: if (acroFields != null && acroFields.getXfa().isChanged()) {
0164: markUsed(acroForm);
0165: if (!flat)
0166: acroFields.getXfa().setXfa(this );
0167: }
0168: if (sigFlags != 0) {
0169: if (acroForm != null) {
0170: acroForm.put(PdfName.SIGFLAGS, new PdfNumber(sigFlags));
0171: markUsed(acroForm);
0172: }
0173: }
0174: closed = true;
0175: addSharedObjectsToBody();
0176: setOutlines();
0177: setJavaScript();
0178: addFileAttachments();
0179: PdfDictionary catalog = reader.getCatalog();
0180: if (openAction != null) {
0181: catalog.put(PdfName.OPENACTION, openAction);
0182: }
0183: if (pdf.pageLabels != null)
0184: catalog.put(PdfName.PAGELABELS, pdf.pageLabels
0185: .getDictionary(this ));
0186: byte[] altMetadata = xmpMetadata;
0187: if (altMetadata == null) {
0188: PdfObject xmpo = PdfReader.getPdfObject(catalog
0189: .get(PdfName.METADATA));
0190: if (xmpo != null && xmpo.isStream()) {
0191: altMetadata = PdfReader
0192: .getStreamBytesRaw((PRStream) xmpo);
0193: PdfReader.killIndirect(xmpo);
0194: }
0195: }
0196: // if there is XMP data to add: add it
0197: if (altMetadata != null) {
0198: PdfStream xmp = new PdfStream(altMetadata);
0199: xmp.put(PdfName.TYPE, PdfName.METADATA);
0200: xmp.put(PdfName.SUBTYPE, PdfName.XML);
0201: if (crypto != null && !crypto.isMetadataEncrypted()) {
0202: PdfArray ar = new PdfArray();
0203: ar.add(PdfName.CRYPT);
0204: xmp.put(PdfName.FILTER, ar);
0205: }
0206: catalog.put(PdfName.METADATA, body.add(xmp)
0207: .getIndirectReference());
0208: markUsed(catalog);
0209: }
0210: PRIndirectReference iInfo = null;
0211: try {
0212: file.reOpen();
0213: alterContents();
0214: iInfo = (PRIndirectReference) reader.trailer
0215: .get(PdfName.INFO);
0216: int skip = -1;
0217: if (iInfo != null)
0218: skip = iInfo.getNumber();
0219: int rootN = ((PRIndirectReference) reader.trailer
0220: .get(PdfName.ROOT)).getNumber();
0221: if (append) {
0222: int keys[] = marked.getKeys();
0223: for (int k = 0; k < keys.length; ++k) {
0224: int j = keys[k];
0225: PdfObject obj = reader.getPdfObjectRelease(j);
0226: if (obj != null && skip != j && j < initialXrefSize) {
0227: addToBody(obj, j, j != rootN);
0228: }
0229: }
0230: for (int k = initialXrefSize; k < reader.getXrefSize(); ++k) {
0231: PdfObject obj = reader.getPdfObject(k);
0232: if (obj != null) {
0233: addToBody(obj, getNewObjectNumber(reader, k, 0));
0234: }
0235: }
0236: } else {
0237: for (int k = 1; k < reader.getXrefSize(); ++k) {
0238: PdfObject obj = reader.getPdfObjectRelease(k);
0239: if (obj != null && skip != k) {
0240: addToBody(obj,
0241: getNewObjectNumber(reader, k, 0),
0242: k != rootN);
0243: }
0244: }
0245: }
0246: } finally {
0247: try {
0248: file.close();
0249: } catch (Exception e) {
0250: // empty on purpose
0251: }
0252: }
0253: PdfIndirectReference encryption = null;
0254: PdfObject fileID = null;
0255: if (crypto != null) {
0256: if (append) {
0257: encryption = reader.getCryptoRef();
0258: } else {
0259: PdfIndirectObject encryptionObject = addToBody(crypto
0260: .getEncryptionDictionary(), false);
0261: encryption = encryptionObject.getIndirectReference();
0262: }
0263: fileID = crypto.getFileID();
0264: } else
0265: fileID = PdfEncryption.createInfoId(PdfEncryption
0266: .createDocumentId());
0267: PRIndirectReference iRoot = (PRIndirectReference) reader.trailer
0268: .get(PdfName.ROOT);
0269: PdfIndirectReference root = new PdfIndirectReference(0,
0270: getNewObjectNumber(reader, iRoot.getNumber(), 0));
0271: PdfIndirectReference info = null;
0272: PdfDictionary oldInfo = (PdfDictionary) PdfReader
0273: .getPdfObject(iInfo);
0274: PdfDictionary newInfo = new PdfDictionary();
0275: if (oldInfo != null) {
0276: for (Iterator i = oldInfo.getKeys().iterator(); i.hasNext();) {
0277: PdfName key = (PdfName) i.next();
0278: PdfObject value = PdfReader.getPdfObject(oldInfo
0279: .get(key));
0280: newInfo.put(key, value);
0281: }
0282: }
0283: if (moreInfo != null) {
0284: for (Iterator i = moreInfo.entrySet().iterator(); i
0285: .hasNext();) {
0286: Map.Entry entry = (Map.Entry) i.next();
0287: String key = (String) entry.getKey();
0288: PdfName keyName = new PdfName(key);
0289: String value = (String) entry.getValue();
0290: if (value == null)
0291: newInfo.remove(keyName);
0292: else
0293: newInfo.put(keyName, new PdfString(value,
0294: PdfObject.TEXT_UNICODE));
0295: }
0296: }
0297: if (append) {
0298: if (iInfo == null)
0299: info = addToBody(newInfo, false).getIndirectReference();
0300: else
0301: info = addToBody(newInfo, iInfo.getNumber(), false)
0302: .getIndirectReference();
0303: } else {
0304: if (!newInfo.getKeys().isEmpty())
0305: info = addToBody(newInfo, false).getIndirectReference();
0306: }
0307: // write the cross-reference table of the body
0308: body.writeCrossReferenceTable(os, root, info, encryption,
0309: fileID, prevxref);
0310: if (fullCompression) {
0311: os.write(getISOBytes("startxref\n"));
0312: os.write(getISOBytes(String.valueOf(body.offset())));
0313: os.write(getISOBytes("\n%%EOF\n"));
0314: } else {
0315: PdfTrailer trailer = new PdfTrailer(body.size(), body
0316: .offset(), root, info, encryption, fileID, prevxref);
0317: trailer.toPdf(this , os);
0318: }
0319: os.flush();
0320: if (isCloseStream())
0321: os.close();
0322: reader.close();
0323: }
0324:
0325: void applyRotation(PdfDictionary pageN, ByteBuffer out) {
0326: if (!rotateContents)
0327: return;
0328: Rectangle page = reader.getPageSizeWithRotation(pageN);
0329: int rotation = page.getRotation();
0330: switch (rotation) {
0331: case 90:
0332: out.append(PdfContents.ROTATE90);
0333: out.append(page.getTop());
0334: out.append(' ').append('0').append(PdfContents.ROTATEFINAL);
0335: break;
0336: case 180:
0337: out.append(PdfContents.ROTATE180);
0338: out.append(page.getRight());
0339: out.append(' ');
0340: out.append(page.getTop());
0341: out.append(PdfContents.ROTATEFINAL);
0342: break;
0343: case 270:
0344: out.append(PdfContents.ROTATE270);
0345: out.append('0').append(' ');
0346: out.append(page.getRight());
0347: out.append(PdfContents.ROTATEFINAL);
0348: break;
0349: }
0350: }
0351:
0352: void alterContents() throws IOException {
0353: for (Iterator i = pagesToContent.values().iterator(); i
0354: .hasNext();) {
0355: PageStamp ps = (PageStamp) i.next();
0356: PdfDictionary pageN = ps.pageN;
0357: markUsed(pageN);
0358: PdfArray ar = null;
0359: PdfObject content = PdfReader.getPdfObject(pageN
0360: .get(PdfName.CONTENTS), pageN);
0361: if (content == null) {
0362: ar = new PdfArray();
0363: pageN.put(PdfName.CONTENTS, ar);
0364: } else if (content.isArray()) {
0365: ar = (PdfArray) content;
0366: markUsed(ar);
0367: } else if (content.isStream()) {
0368: ar = new PdfArray();
0369: ar.add(pageN.get(PdfName.CONTENTS));
0370: pageN.put(PdfName.CONTENTS, ar);
0371: } else {
0372: ar = new PdfArray();
0373: pageN.put(PdfName.CONTENTS, ar);
0374: }
0375: ByteBuffer out = new ByteBuffer();
0376: if (ps.under != null) {
0377: out.append(PdfContents.SAVESTATE);
0378: applyRotation(pageN, out);
0379: out.append(ps.under.getInternalBuffer());
0380: out.append(PdfContents.RESTORESTATE);
0381: }
0382: if (ps.over != null)
0383: out.append(PdfContents.SAVESTATE);
0384: PdfStream stream = new PdfStream(out.toByteArray());
0385: stream.flateCompress();
0386: ar.addFirst(addToBody(stream).getIndirectReference());
0387: out.reset();
0388: if (ps.over != null) {
0389: out.append(' ');
0390: out.append(PdfContents.RESTORESTATE);
0391: out.append(PdfContents.SAVESTATE);
0392: applyRotation(pageN, out);
0393: out.append(ps.over.getInternalBuffer());
0394: out.append(PdfContents.RESTORESTATE);
0395: stream = new PdfStream(out.toByteArray());
0396: stream.flateCompress();
0397: ar.add(addToBody(stream).getIndirectReference());
0398: }
0399: alterResources(ps);
0400: }
0401: }
0402:
0403: void alterResources(PageStamp ps) {
0404: ps.pageN
0405: .put(PdfName.RESOURCES, ps.pageResources.getResources());
0406: }
0407:
0408: protected int getNewObjectNumber(PdfReader reader, int number,
0409: int generation) {
0410: IntHashtable ref = (IntHashtable) readers2intrefs.get(reader);
0411: if (ref != null) {
0412: int n = ref.get(number);
0413: if (n == 0) {
0414: n = getIndirectReferenceNumber();
0415: ref.put(number, n);
0416: }
0417: return n;
0418: }
0419: if (currentPdfReaderInstance == null) {
0420: if (append && number < initialXrefSize)
0421: return number;
0422: int n = myXref.get(number);
0423: if (n == 0) {
0424: n = getIndirectReferenceNumber();
0425: myXref.put(number, n);
0426: }
0427: return n;
0428: } else
0429: return currentPdfReaderInstance.getNewObjectNumber(number,
0430: generation);
0431: }
0432:
0433: RandomAccessFileOrArray getReaderFile(PdfReader reader) {
0434: if (readers2intrefs.containsKey(reader)) {
0435: RandomAccessFileOrArray raf = (RandomAccessFileOrArray) readers2file
0436: .get(reader);
0437: if (raf != null)
0438: return raf;
0439: return reader.getSafeFile();
0440: }
0441: if (currentPdfReaderInstance == null)
0442: return file;
0443: else
0444: return currentPdfReaderInstance.getReaderFile();
0445: }
0446:
0447: /**
0448: * @param reader
0449: * @param openFile
0450: * @throws IOException
0451: */
0452: public void registerReader(PdfReader reader, boolean openFile)
0453: throws IOException {
0454: if (readers2intrefs.containsKey(reader))
0455: return;
0456: readers2intrefs.put(reader, new IntHashtable());
0457: if (openFile) {
0458: RandomAccessFileOrArray raf = reader.getSafeFile();
0459: readers2file.put(reader, raf);
0460: raf.reOpen();
0461: }
0462: }
0463:
0464: /**
0465: * @param reader
0466: */
0467: public void unRegisterReader(PdfReader reader) {
0468: if (!readers2intrefs.containsKey(reader))
0469: return;
0470: readers2intrefs.remove(reader);
0471: RandomAccessFileOrArray raf = (RandomAccessFileOrArray) readers2file
0472: .get(reader);
0473: if (raf == null)
0474: return;
0475: readers2file.remove(reader);
0476: try {
0477: raf.close();
0478: } catch (Exception e) {
0479: }
0480: }
0481:
0482: static void findAllObjects(PdfReader reader, PdfObject obj,
0483: IntHashtable hits) {
0484: if (obj == null)
0485: return;
0486: switch (obj.type()) {
0487: case PdfObject.INDIRECT:
0488: PRIndirectReference iref = (PRIndirectReference) obj;
0489: if (reader != iref.getReader())
0490: return;
0491: if (hits.containsKey(iref.getNumber()))
0492: return;
0493: hits.put(iref.getNumber(), 1);
0494: findAllObjects(reader, PdfReader.getPdfObject(obj), hits);
0495: return;
0496: case PdfObject.ARRAY:
0497: ArrayList lst = ((PdfArray) obj).getArrayList();
0498: for (int k = 0; k < lst.size(); ++k) {
0499: findAllObjects(reader, (PdfObject) lst.get(k), hits);
0500: }
0501: return;
0502: case PdfObject.DICTIONARY:
0503: case PdfObject.STREAM:
0504: PdfDictionary dic = (PdfDictionary) obj;
0505: for (Iterator it = dic.getKeys().iterator(); it.hasNext();) {
0506: PdfName name = (PdfName) it.next();
0507: findAllObjects(reader, dic.get(name), hits);
0508: }
0509: return;
0510: }
0511: }
0512:
0513: /**
0514: * @param fdf
0515: * @throws IOException
0516: */
0517: public void addComments(FdfReader fdf) throws IOException {
0518: if (readers2intrefs.containsKey(fdf))
0519: return;
0520: PdfDictionary catalog = fdf.getCatalog();
0521: catalog = (PdfDictionary) PdfReader.getPdfObject(catalog
0522: .get(PdfName.FDF));
0523: if (catalog == null)
0524: return;
0525: PdfArray annots = (PdfArray) PdfReader.getPdfObject(catalog
0526: .get(PdfName.ANNOTS));
0527: if (annots == null || annots.size() == 0)
0528: return;
0529: registerReader(fdf, false);
0530: IntHashtable hits = new IntHashtable();
0531: HashMap irt = new HashMap();
0532: ArrayList an = new ArrayList();
0533: ArrayList ar = annots.getArrayList();
0534: for (int k = 0; k < ar.size(); ++k) {
0535: PdfObject obj = (PdfObject) ar.get(k);
0536: PdfDictionary annot = (PdfDictionary) PdfReader
0537: .getPdfObject(obj);
0538: PdfNumber page = (PdfNumber) PdfReader.getPdfObject(annot
0539: .get(PdfName.PAGE));
0540: if (page == null
0541: || page.intValue() >= reader.getNumberOfPages())
0542: continue;
0543: findAllObjects(fdf, obj, hits);
0544: an.add(obj);
0545: if (obj.type() == PdfObject.INDIRECT) {
0546: PdfObject nm = PdfReader.getPdfObject(annot
0547: .get(PdfName.NM));
0548: if (nm != null && nm.type() == PdfObject.STRING)
0549: irt.put(nm.toString(), obj);
0550: }
0551: }
0552: int arhits[] = hits.getKeys();
0553: for (int k = 0; k < arhits.length; ++k) {
0554: int n = arhits[k];
0555: PdfObject obj = fdf.getPdfObject(n);
0556: if (obj.type() == PdfObject.DICTIONARY) {
0557: PdfObject str = PdfReader
0558: .getPdfObject(((PdfDictionary) obj)
0559: .get(PdfName.IRT));
0560: if (str != null && str.type() == PdfObject.STRING) {
0561: PdfObject i = (PdfObject) irt.get(str.toString());
0562: if (i != null) {
0563: PdfDictionary dic2 = new PdfDictionary();
0564: dic2.merge((PdfDictionary) obj);
0565: dic2.put(PdfName.IRT, i);
0566: obj = dic2;
0567: }
0568: }
0569: }
0570: addToBody(obj, getNewObjectNumber(fdf, n, 0));
0571: }
0572: for (int k = 0; k < an.size(); ++k) {
0573: PdfObject obj = (PdfObject) an.get(k);
0574: PdfDictionary annot = (PdfDictionary) PdfReader
0575: .getPdfObject(obj);
0576: PdfNumber page = (PdfNumber) PdfReader.getPdfObject(annot
0577: .get(PdfName.PAGE));
0578: PdfDictionary dic = reader.getPageN(page.intValue() + 1);
0579: PdfArray annotsp = (PdfArray) PdfReader.getPdfObject(dic
0580: .get(PdfName.ANNOTS), dic);
0581: if (annotsp == null) {
0582: annotsp = new PdfArray();
0583: dic.put(PdfName.ANNOTS, annotsp);
0584: markUsed(dic);
0585: }
0586: markUsed(annotsp);
0587: annotsp.add(obj);
0588: }
0589: }
0590:
0591: PageStamp getPageStamp(int pageNum) {
0592: PdfDictionary pageN = reader.getPageN(pageNum);
0593: PageStamp ps = (PageStamp) pagesToContent.get(pageN);
0594: if (ps == null) {
0595: ps = new PageStamp(this , reader, pageN);
0596: pagesToContent.put(pageN, ps);
0597: }
0598: return ps;
0599: }
0600:
0601: PdfContentByte getUnderContent(int pageNum) {
0602: if (pageNum < 1 || pageNum > reader.getNumberOfPages())
0603: return null;
0604: PageStamp ps = getPageStamp(pageNum);
0605: if (ps.under == null)
0606: ps.under = new StampContent(this , ps);
0607: return ps.under;
0608: }
0609:
0610: PdfContentByte getOverContent(int pageNum) {
0611: if (pageNum < 1 || pageNum > reader.getNumberOfPages())
0612: return null;
0613: PageStamp ps = getPageStamp(pageNum);
0614: if (ps.over == null)
0615: ps.over = new StampContent(this , ps);
0616: return ps.over;
0617: }
0618:
0619: void correctAcroFieldPages(int page) {
0620: if (acroFields == null)
0621: return;
0622: if (page > reader.getNumberOfPages())
0623: return;
0624: HashMap fields = acroFields.getFields();
0625: for (Iterator it = fields.values().iterator(); it.hasNext();) {
0626: AcroFields.Item item = (AcroFields.Item) it.next();
0627: ArrayList pages = item.page;
0628: for (int k = 0; k < pages.size(); ++k) {
0629: int p = ((Integer) pages.get(k)).intValue();
0630: if (p >= page)
0631: pages.set(k, new Integer(p + 1));
0632: }
0633: }
0634: }
0635:
0636: void insertPage(int pageNumber, Rectangle mediabox) {
0637: Rectangle media = new Rectangle(mediabox);
0638: int rotation = media.getRotation() % 360;
0639: PdfDictionary page = new PdfDictionary(PdfName.PAGE);
0640: PdfDictionary resources = new PdfDictionary();
0641: PdfArray procset = new PdfArray();
0642: procset.add(PdfName.PDF);
0643: procset.add(PdfName.TEXT);
0644: procset.add(PdfName.IMAGEB);
0645: procset.add(PdfName.IMAGEC);
0646: procset.add(PdfName.IMAGEI);
0647: resources.put(PdfName.PROCSET, procset);
0648: page.put(PdfName.RESOURCES, resources);
0649: page.put(PdfName.ROTATE, new PdfNumber(rotation));
0650: page.put(PdfName.MEDIABOX, new PdfRectangle(media, rotation));
0651: PRIndirectReference pref = reader.addPdfObject(page);
0652: PdfDictionary parent;
0653: PRIndirectReference parentRef;
0654: if (pageNumber > reader.getNumberOfPages()) {
0655: PdfDictionary lastPage = reader.getPageNRelease(reader
0656: .getNumberOfPages());
0657: parentRef = (PRIndirectReference) lastPage
0658: .get(PdfName.PARENT);
0659: parentRef = new PRIndirectReference(reader, parentRef
0660: .getNumber());
0661: parent = (PdfDictionary) PdfReader.getPdfObject(parentRef);
0662: PdfArray kids = (PdfArray) PdfReader.getPdfObject(parent
0663: .get(PdfName.KIDS), parent);
0664: kids.add(pref);
0665: markUsed(kids);
0666: reader.pageRefs.insertPage(pageNumber, pref);
0667: } else {
0668: if (pageNumber < 1)
0669: pageNumber = 1;
0670: PdfDictionary firstPage = reader.getPageN(pageNumber);
0671: PRIndirectReference firstPageRef = reader
0672: .getPageOrigRef(pageNumber);
0673: reader.releasePage(pageNumber);
0674: parentRef = (PRIndirectReference) firstPage
0675: .get(PdfName.PARENT);
0676: parentRef = new PRIndirectReference(reader, parentRef
0677: .getNumber());
0678: parent = (PdfDictionary) PdfReader.getPdfObject(parentRef);
0679: PdfArray kids = (PdfArray) PdfReader.getPdfObject(parent
0680: .get(PdfName.KIDS), parent);
0681: ArrayList ar = kids.getArrayList();
0682: int len = ar.size();
0683: int num = firstPageRef.getNumber();
0684: for (int k = 0; k < len; ++k) {
0685: PRIndirectReference cur = (PRIndirectReference) ar
0686: .get(k);
0687: if (num == cur.getNumber()) {
0688: ar.add(k, pref);
0689: break;
0690: }
0691: }
0692: if (len == ar.size())
0693: throw new RuntimeException("Internal inconsistence.");
0694: markUsed(kids);
0695: reader.pageRefs.insertPage(pageNumber, pref);
0696: correctAcroFieldPages(pageNumber);
0697: }
0698: page.put(PdfName.PARENT, parentRef);
0699: while (parent != null) {
0700: markUsed(parent);
0701: PdfNumber count = (PdfNumber) PdfReader
0702: .getPdfObjectRelease(parent.get(PdfName.COUNT));
0703: parent.put(PdfName.COUNT, new PdfNumber(
0704: count.intValue() + 1));
0705: parent = (PdfDictionary) PdfReader.getPdfObject(parent
0706: .get(PdfName.PARENT));
0707: }
0708: }
0709:
0710: /** Getter for property rotateContents.
0711: * @return Value of property rotateContents.
0712: *
0713: */
0714: boolean isRotateContents() {
0715: return this .rotateContents;
0716: }
0717:
0718: /** Setter for property rotateContents.
0719: * @param rotateContents New value of property rotateContents.
0720: *
0721: */
0722: void setRotateContents(boolean rotateContents) {
0723: this .rotateContents = rotateContents;
0724: }
0725:
0726: boolean isContentWritten() {
0727: return body.size() > 1;
0728: }
0729:
0730: AcroFields getAcroFields() {
0731: if (acroFields == null) {
0732: acroFields = new AcroFields(reader, this );
0733: }
0734: return acroFields;
0735: }
0736:
0737: void setFormFlattening(boolean flat) {
0738: this .flat = flat;
0739: }
0740:
0741: void setFreeTextFlattening(boolean flat) {
0742: this .flatFreeText = flat;
0743: }
0744:
0745: boolean partialFormFlattening(String name) {
0746: getAcroFields();
0747: if (acroFields.getXfa().isXfaPresent())
0748: throw new UnsupportedOperationException(
0749: "Partial form flattening is not supported with XFA forms.");
0750: if (!acroFields.getFields().containsKey(name))
0751: return false;
0752: partialFlattening.add(name);
0753: return true;
0754: }
0755:
0756: void flatFields() {
0757: if (append)
0758: throw new IllegalArgumentException(
0759: "Field flattening is not supported in append mode.");
0760: getAcroFields();
0761: HashMap fields = acroFields.getFields();
0762: if (fieldsAdded && partialFlattening.isEmpty()) {
0763: for (Iterator i = fields.keySet().iterator(); i.hasNext();) {
0764: partialFlattening.add(i.next());
0765: }
0766: }
0767: PdfDictionary acroForm = (PdfDictionary) PdfReader
0768: .getPdfObject(reader.getCatalog().get(PdfName.ACROFORM));
0769: ArrayList acroFds = null;
0770: if (acroForm != null) {
0771: PdfArray array = (PdfArray) PdfReader.getPdfObject(acroForm
0772: .get(PdfName.FIELDS), acroForm);
0773: if (array != null)
0774: acroFds = array.getArrayList();
0775: }
0776: for (Iterator i = fields.entrySet().iterator(); i.hasNext();) {
0777: Map.Entry entry = (Map.Entry) i.next();
0778: String name = (String) entry.getKey();
0779: if (!partialFlattening.isEmpty()
0780: && !partialFlattening.contains(name))
0781: continue;
0782: AcroFields.Item item = (AcroFields.Item) entry.getValue();
0783: for (int k = 0; k < item.merged.size(); ++k) {
0784: PdfDictionary merged = (PdfDictionary) item.merged
0785: .get(k);
0786: PdfNumber ff = (PdfNumber) PdfReader
0787: .getPdfObject(merged.get(PdfName.F));
0788: int flags = 0;
0789: if (ff != null)
0790: flags = ff.intValue();
0791: int page = ((Integer) item.page.get(k)).intValue();
0792: PdfDictionary appDic = (PdfDictionary) PdfReader
0793: .getPdfObject(merged.get(PdfName.AP));
0794: if (appDic != null
0795: && (flags & PdfFormField.FLAGS_PRINT) != 0
0796: && (flags & PdfFormField.FLAGS_HIDDEN) == 0) {
0797: PdfObject obj = appDic.get(PdfName.N);
0798: PdfAppearance app = null;
0799: if (obj != null) {
0800: PdfObject objReal = PdfReader.getPdfObject(obj);
0801: if (obj instanceof PdfIndirectReference
0802: && !obj.isIndirect())
0803: app = new PdfAppearance(
0804: (PdfIndirectReference) obj);
0805: else if (objReal instanceof PdfStream) {
0806: ((PdfDictionary) objReal).put(
0807: PdfName.SUBTYPE, PdfName.FORM);
0808: app = new PdfAppearance(
0809: (PdfIndirectReference) obj);
0810: } else {
0811: if (objReal != null
0812: && objReal.isDictionary()) {
0813: PdfName as = (PdfName) PdfReader
0814: .getPdfObject(merged
0815: .get(PdfName.AS));
0816: if (as != null) {
0817: PdfIndirectReference iref = (PdfIndirectReference) ((PdfDictionary) objReal)
0818: .get(as);
0819: if (iref != null) {
0820: app = new PdfAppearance(iref);
0821: if (iref.isIndirect()) {
0822: objReal = PdfReader
0823: .getPdfObject(iref);
0824: ((PdfDictionary) objReal)
0825: .put(
0826: PdfName.SUBTYPE,
0827: PdfName.FORM);
0828: }
0829: }
0830: }
0831: }
0832: }
0833: }
0834: if (app != null) {
0835: Rectangle box = PdfReader
0836: .getNormalizedRectangle((PdfArray) PdfReader
0837: .getPdfObject(merged
0838: .get(PdfName.RECT)));
0839: PdfContentByte cb = getOverContent(page);
0840: cb.setLiteral("Q ");
0841: cb.addTemplate(app, box.getLeft(), box
0842: .getBottom());
0843: cb.setLiteral("q ");
0844: }
0845: }
0846: if (partialFlattening.isEmpty())
0847: continue;
0848: PdfDictionary pageDic = reader.getPageN(page);
0849: PdfArray annots = (PdfArray) PdfReader
0850: .getPdfObject(pageDic.get(PdfName.ANNOTS));
0851: if (annots == null)
0852: continue;
0853: ArrayList ar = annots.getArrayList();
0854: for (int idx = 0; idx < ar.size(); ++idx) {
0855: PdfObject ran = (PdfObject) ar.get(idx);
0856: if (!ran.isIndirect())
0857: continue;
0858: PdfObject ran2 = (PdfObject) item.widget_refs
0859: .get(k);
0860: if (!ran2.isIndirect())
0861: continue;
0862: if (((PRIndirectReference) ran).getNumber() == ((PRIndirectReference) ran2)
0863: .getNumber()) {
0864: ar.remove(idx--);
0865: PRIndirectReference wdref = (PRIndirectReference) ran2;
0866: while (true) {
0867: PdfDictionary wd = (PdfDictionary) PdfReader
0868: .getPdfObject(wdref);
0869: PRIndirectReference parentRef = (PRIndirectReference) wd
0870: .get(PdfName.PARENT);
0871: PdfReader.killIndirect(wdref);
0872: if (parentRef == null) { // reached AcroForm
0873: for (int fr = 0; fr < acroFds.size(); ++fr) {
0874: PdfObject h = (PdfObject) acroFds
0875: .get(fr);
0876: if (h.isIndirect()
0877: && ((PRIndirectReference) h)
0878: .getNumber() == wdref
0879: .getNumber()) {
0880: acroFds.remove(fr);
0881: --fr;
0882: }
0883: }
0884: break;
0885: }
0886: PdfDictionary parent = (PdfDictionary) PdfReader
0887: .getPdfObject(parentRef);
0888: PdfArray kids = (PdfArray) PdfReader
0889: .getPdfObject(parent
0890: .get(PdfName.KIDS));
0891: ArrayList kar = kids.getArrayList();
0892: for (int fr = 0; fr < kar.size(); ++fr) {
0893: PdfObject h = (PdfObject) kar.get(fr);
0894: if (h.isIndirect()
0895: && ((PRIndirectReference) h)
0896: .getNumber() == wdref
0897: .getNumber()) {
0898: kar.remove(fr);
0899: --fr;
0900: }
0901: }
0902: if (!kar.isEmpty())
0903: break;
0904: wdref = parentRef;
0905: }
0906: }
0907: }
0908: if (ar.isEmpty()) {
0909: PdfReader.killIndirect(pageDic.get(PdfName.ANNOTS));
0910: pageDic.remove(PdfName.ANNOTS);
0911: }
0912: }
0913: }
0914: if (!fieldsAdded && partialFlattening.isEmpty()) {
0915: for (int page = 1; page <= reader.getNumberOfPages(); ++page) {
0916: PdfDictionary pageDic = reader.getPageN(page);
0917: PdfArray annots = (PdfArray) PdfReader
0918: .getPdfObject(pageDic.get(PdfName.ANNOTS));
0919: if (annots == null)
0920: continue;
0921: ArrayList ar = annots.getArrayList();
0922: for (int idx = 0; idx < ar.size(); ++idx) {
0923: PdfObject annoto = PdfReader
0924: .getPdfObject((PdfObject) ar.get(idx));
0925: if ((annoto instanceof PdfIndirectReference)
0926: && !annoto.isIndirect())
0927: continue;
0928: if (!annoto.isDictionary()
0929: || PdfName.WIDGET
0930: .equals(((PdfDictionary) annoto)
0931: .get(PdfName.SUBTYPE))) {
0932: ar.remove(idx);
0933: --idx;
0934: }
0935: }
0936: if (ar.isEmpty()) {
0937: PdfReader.killIndirect(pageDic.get(PdfName.ANNOTS));
0938: pageDic.remove(PdfName.ANNOTS);
0939: }
0940: }
0941: eliminateAcroformObjects();
0942: }
0943: }
0944:
0945: void eliminateAcroformObjects() {
0946: PdfObject acro = reader.getCatalog().get(PdfName.ACROFORM);
0947: if (acro == null)
0948: return;
0949: PdfDictionary acrodic = (PdfDictionary) PdfReader
0950: .getPdfObject(acro);
0951: reader.killXref(acrodic.get(PdfName.XFA));
0952: acrodic.remove(PdfName.XFA);
0953: PdfObject iFields = acrodic.get(PdfName.FIELDS);
0954: if (iFields != null) {
0955: PdfDictionary kids = new PdfDictionary();
0956: kids.put(PdfName.KIDS, iFields);
0957: sweepKids(kids);
0958: PdfReader.killIndirect(iFields);
0959: acrodic.put(PdfName.FIELDS, new PdfArray());
0960: }
0961: // PdfReader.killIndirect(acro);
0962: // reader.getCatalog().remove(PdfName.ACROFORM);
0963: }
0964:
0965: void sweepKids(PdfObject obj) {
0966: PdfObject oo = PdfReader.killIndirect(obj);
0967: if (oo == null || !oo.isDictionary())
0968: return;
0969: PdfDictionary dic = (PdfDictionary) oo;
0970: PdfArray kids = (PdfArray) PdfReader.killIndirect(dic
0971: .get(PdfName.KIDS));
0972: if (kids == null)
0973: return;
0974: ArrayList ar = kids.getArrayList();
0975: for (int k = 0; k < ar.size(); ++k) {
0976: sweepKids((PdfObject) ar.get(k));
0977: }
0978: }
0979:
0980: private void flatFreeTextFields() {
0981: if (append)
0982: throw new IllegalArgumentException(
0983: "FreeText flattening is not supported in append mode.");
0984:
0985: for (int page = 1; page <= reader.getNumberOfPages(); ++page) {
0986: PdfDictionary pageDic = reader.getPageN(page);
0987: PdfArray annots = (PdfArray) PdfReader.getPdfObject(pageDic
0988: .get(PdfName.ANNOTS));
0989: if (annots == null)
0990: continue;
0991: ArrayList ar = annots.getArrayList();
0992: for (int idx = 0; idx < ar.size(); ++idx) {
0993: PdfObject annoto = PdfReader
0994: .getPdfObject((PdfObject) ar.get(idx));
0995: if ((annoto instanceof PdfIndirectReference)
0996: && !annoto.isIndirect())
0997: continue;
0998:
0999: PdfDictionary annDic = (PdfDictionary) annoto;
1000: if (!((PdfName) annDic.get(PdfName.SUBTYPE))
1001: .equals(PdfName.FREETEXT))
1002: continue;
1003: PdfNumber ff = (PdfNumber) PdfReader
1004: .getPdfObject(annDic.get(PdfName.F));
1005: int flags = (ff != null) ? ff.intValue() : 0;
1006:
1007: if ((flags & PdfFormField.FLAGS_PRINT) != 0
1008: && (flags & PdfFormField.FLAGS_HIDDEN) == 0) {
1009: PdfObject obj1 = annDic.get(PdfName.AP);
1010: if (obj1 == null)
1011: continue;
1012: PdfDictionary appDic = (obj1 instanceof PdfIndirectReference) ? (PdfDictionary) PdfReader
1013: .getPdfObject(obj1)
1014: : (PdfDictionary) obj1;
1015: PdfObject obj = appDic.get(PdfName.N);
1016: PdfAppearance app = null;
1017: PdfObject objReal = PdfReader.getPdfObject(obj);
1018:
1019: if (obj instanceof PdfIndirectReference
1020: && !obj.isIndirect())
1021: app = new PdfAppearance(
1022: (PdfIndirectReference) obj);
1023: else if (objReal instanceof PdfStream) {
1024: ((PdfDictionary) objReal).put(PdfName.SUBTYPE,
1025: PdfName.FORM);
1026: app = new PdfAppearance(
1027: (PdfIndirectReference) obj);
1028: } else {
1029: if (objReal.isDictionary()) {
1030: PdfName as_p = (PdfName) PdfReader
1031: .getPdfObject(appDic
1032: .get(PdfName.AS));
1033: if (as_p != null) {
1034: PdfIndirectReference iref = (PdfIndirectReference) ((PdfDictionary) objReal)
1035: .get(as_p);
1036: if (iref != null) {
1037: app = new PdfAppearance(iref);
1038: if (iref.isIndirect()) {
1039: objReal = PdfReader
1040: .getPdfObject(iref);
1041: ((PdfDictionary) objReal).put(
1042: PdfName.SUBTYPE,
1043: PdfName.FORM);
1044: }
1045: }
1046: }
1047: }
1048: }
1049: if (app != null) {
1050: Rectangle box = PdfReader
1051: .getNormalizedRectangle((PdfArray) PdfReader
1052: .getPdfObject(annDic
1053: .get(PdfName.RECT)));
1054: PdfContentByte cb = getOverContent(page);
1055: cb.setLiteral("Q ");
1056: cb.addTemplate(app, box.getLeft(), box
1057: .getBottom());
1058: cb.setLiteral("q ");
1059: }
1060: }
1061: }
1062: for (int idx = 0; idx < ar.size(); ++idx) {
1063: PdfObject annoto = PdfReader
1064: .getPdfObject((PdfObject) ar.get(idx));
1065: if (annoto != null && annoto.isDictionary()) {
1066: PdfDictionary annot = (PdfDictionary) annoto;
1067: if (PdfName.FREETEXT.equals(annot
1068: .get(PdfName.SUBTYPE))) {
1069: ar.remove(idx);
1070: --idx;
1071: }
1072: }
1073: }
1074: if (ar.isEmpty()) {
1075: PdfReader.killIndirect(pageDic.get(PdfName.ANNOTS));
1076: pageDic.remove(PdfName.ANNOTS);
1077: }
1078: }
1079: }
1080:
1081: /**
1082: * @see com.lowagie.text.pdf.PdfWriter#getPageReference(int)
1083: */
1084: public PdfIndirectReference getPageReference(int page) {
1085: PdfIndirectReference ref = reader.getPageOrigRef(page);
1086: if (ref == null)
1087: throw new IllegalArgumentException("Invalid page number "
1088: + page);
1089: return ref;
1090: }
1091:
1092: /**
1093: * @see com.lowagie.text.pdf.PdfWriter#addAnnotation(com.lowagie.text.pdf.PdfAnnotation)
1094: */
1095: public void addAnnotation(PdfAnnotation annot) {
1096: throw new RuntimeException(
1097: "Unsupported in this context. Use PdfStamper.addAnnotation()");
1098: }
1099:
1100: void addDocumentField(PdfIndirectReference ref) {
1101: PdfDictionary catalog = reader.getCatalog();
1102: PdfDictionary acroForm = (PdfDictionary) PdfReader
1103: .getPdfObject(catalog.get(PdfName.ACROFORM), catalog);
1104: if (acroForm == null) {
1105: acroForm = new PdfDictionary();
1106: catalog.put(PdfName.ACROFORM, acroForm);
1107: markUsed(catalog);
1108: }
1109: PdfArray fields = (PdfArray) PdfReader.getPdfObject(acroForm
1110: .get(PdfName.FIELDS), acroForm);
1111: if (fields == null) {
1112: fields = new PdfArray();
1113: acroForm.put(PdfName.FIELDS, fields);
1114: markUsed(acroForm);
1115: }
1116: if (!acroForm.contains(PdfName.DA)) {
1117: acroForm.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g "));
1118: markUsed(acroForm);
1119: }
1120: fields.add(ref);
1121: markUsed(fields);
1122: }
1123:
1124: void addFieldResources() throws IOException {
1125: if (fieldTemplates.isEmpty())
1126: return;
1127: PdfDictionary catalog = reader.getCatalog();
1128: PdfDictionary acroForm = (PdfDictionary) PdfReader
1129: .getPdfObject(catalog.get(PdfName.ACROFORM), catalog);
1130: if (acroForm == null) {
1131: acroForm = new PdfDictionary();
1132: catalog.put(PdfName.ACROFORM, acroForm);
1133: markUsed(catalog);
1134: }
1135: PdfDictionary dr = (PdfDictionary) PdfReader.getPdfObject(
1136: acroForm.get(PdfName.DR), acroForm);
1137: if (dr == null) {
1138: dr = new PdfDictionary();
1139: acroForm.put(PdfName.DR, dr);
1140: markUsed(acroForm);
1141: }
1142: markUsed(dr);
1143: for (Iterator it = fieldTemplates.keySet().iterator(); it
1144: .hasNext();) {
1145: PdfTemplate template = (PdfTemplate) it.next();
1146: PdfFormField.mergeResources(dr, (PdfDictionary) template
1147: .getResources(), this );
1148: }
1149: if (dr.get(PdfName.ENCODING) == null)
1150: dr.put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING);
1151: PdfDictionary fonts = (PdfDictionary) PdfReader.getPdfObject(dr
1152: .get(PdfName.FONT));
1153: if (fonts == null) {
1154: fonts = new PdfDictionary();
1155: dr.put(PdfName.FONT, fonts);
1156: }
1157: if (!fonts.contains(PdfName.HELV)) {
1158: PdfDictionary dic = new PdfDictionary(PdfName.FONT);
1159: dic.put(PdfName.BASEFONT, PdfName.HELVETICA);
1160: dic.put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING);
1161: dic.put(PdfName.NAME, PdfName.HELV);
1162: dic.put(PdfName.SUBTYPE, PdfName.TYPE1);
1163: fonts.put(PdfName.HELV, addToBody(dic)
1164: .getIndirectReference());
1165: }
1166: if (!fonts.contains(PdfName.ZADB)) {
1167: PdfDictionary dic = new PdfDictionary(PdfName.FONT);
1168: dic.put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS);
1169: dic.put(PdfName.NAME, PdfName.ZADB);
1170: dic.put(PdfName.SUBTYPE, PdfName.TYPE1);
1171: fonts.put(PdfName.ZADB, addToBody(dic)
1172: .getIndirectReference());
1173: }
1174: if (acroForm.get(PdfName.DA) == null) {
1175: acroForm.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g "));
1176: markUsed(acroForm);
1177: }
1178: }
1179:
1180: void expandFields(PdfFormField field, ArrayList allAnnots) {
1181: allAnnots.add(field);
1182: ArrayList kids = field.getKids();
1183: if (kids != null) {
1184: for (int k = 0; k < kids.size(); ++k)
1185: expandFields((PdfFormField) kids.get(k), allAnnots);
1186: }
1187: }
1188:
1189: void addAnnotation(PdfAnnotation annot, PdfDictionary pageN) {
1190: try {
1191: ArrayList allAnnots = new ArrayList();
1192: if (annot.isForm()) {
1193: fieldsAdded = true;
1194: getAcroFields();
1195: PdfFormField field = (PdfFormField) annot;
1196: if (field.getParent() != null)
1197: return;
1198: expandFields(field, allAnnots);
1199: } else
1200: allAnnots.add(annot);
1201: for (int k = 0; k < allAnnots.size(); ++k) {
1202: annot = (PdfAnnotation) allAnnots.get(k);
1203: if (annot.getPlaceInPage() > 0)
1204: pageN = reader.getPageN(annot.getPlaceInPage());
1205: if (annot.isForm()) {
1206: if (!annot.isUsed()) {
1207: HashMap templates = annot.getTemplates();
1208: if (templates != null)
1209: fieldTemplates.putAll(templates);
1210: }
1211: PdfFormField field = (PdfFormField) annot;
1212: if (field.getParent() == null)
1213: addDocumentField(field.getIndirectReference());
1214: }
1215: if (annot.isAnnotation()) {
1216: PdfObject pdfobj = PdfReader.getPdfObject(pageN
1217: .get(PdfName.ANNOTS), pageN);
1218: PdfArray annots = null;
1219: if (pdfobj == null || !pdfobj.isArray()) {
1220: annots = new PdfArray();
1221: pageN.put(PdfName.ANNOTS, annots);
1222: markUsed(pageN);
1223: } else
1224: annots = (PdfArray) pdfobj;
1225: annots.add(annot.getIndirectReference());
1226: markUsed(annots);
1227: if (!annot.isUsed()) {
1228: PdfRectangle rect = (PdfRectangle) annot
1229: .get(PdfName.RECT);
1230: if (rect != null
1231: && (rect.left() != 0
1232: || rect.right() != 0
1233: || rect.top() != 0 || rect
1234: .bottom() != 0)) {
1235: int rotation = reader
1236: .getPageRotation(pageN);
1237: Rectangle pageSize = reader
1238: .getPageSizeWithRotation(pageN);
1239: switch (rotation) {
1240: case 90:
1241: annot.put(PdfName.RECT,
1242: new PdfRectangle(pageSize
1243: .getTop()
1244: - rect.bottom(), rect
1245: .left(), pageSize
1246: .getTop()
1247: - rect.top(), rect
1248: .right()));
1249: break;
1250: case 180:
1251: annot.put(PdfName.RECT,
1252: new PdfRectangle(pageSize
1253: .getRight()
1254: - rect.left(), pageSize
1255: .getTop()
1256: - rect.bottom(),
1257: pageSize.getRight()
1258: - rect.right(),
1259: pageSize.getTop()
1260: - rect.top()));
1261: break;
1262: case 270:
1263: annot
1264: .put(
1265: PdfName.RECT,
1266: new PdfRectangle(
1267: rect.bottom(),
1268: pageSize
1269: .getRight()
1270: - rect
1271: .left(),
1272: rect.top(),
1273: pageSize
1274: .getRight()
1275: - rect
1276: .right()));
1277: break;
1278: }
1279: }
1280: }
1281: }
1282: if (!annot.isUsed()) {
1283: annot.setUsed();
1284: addToBody(annot, annot.getIndirectReference());
1285: }
1286: }
1287: } catch (IOException e) {
1288: throw new ExceptionConverter(e);
1289: }
1290: }
1291:
1292: void addAnnotation(PdfAnnotation annot, int page) {
1293: addAnnotation(annot, reader.getPageN(page));
1294: }
1295:
1296: private void outlineTravel(PRIndirectReference outline) {
1297: while (outline != null) {
1298: PdfDictionary outlineR = (PdfDictionary) PdfReader
1299: .getPdfObjectRelease(outline);
1300: PRIndirectReference first = (PRIndirectReference) outlineR
1301: .get(PdfName.FIRST);
1302: if (first != null) {
1303: outlineTravel(first);
1304: }
1305: PdfReader.killIndirect(outlineR.get(PdfName.DEST));
1306: PdfReader.killIndirect(outlineR.get(PdfName.A));
1307: PdfReader.killIndirect(outline);
1308: outline = (PRIndirectReference) outlineR.get(PdfName.NEXT);
1309: }
1310: }
1311:
1312: void deleteOutlines() {
1313: PdfDictionary catalog = reader.getCatalog();
1314: PRIndirectReference outlines = (PRIndirectReference) catalog
1315: .get(PdfName.OUTLINES);
1316: if (outlines == null)
1317: return;
1318: outlineTravel(outlines);
1319: PdfReader.killIndirect(outlines);
1320: catalog.remove(PdfName.OUTLINES);
1321: markUsed(catalog);
1322: }
1323:
1324: void setJavaScript() throws IOException {
1325: HashMap djs = pdf.getDocumentLevelJS();
1326: if (djs.isEmpty())
1327: return;
1328: PdfDictionary catalog = reader.getCatalog();
1329: PdfDictionary names = (PdfDictionary) PdfReader.getPdfObject(
1330: catalog.get(PdfName.NAMES), catalog);
1331: if (names == null) {
1332: names = new PdfDictionary();
1333: catalog.put(PdfName.NAMES, names);
1334: markUsed(catalog);
1335: }
1336: markUsed(names);
1337: PdfDictionary tree = PdfNameTree.writeTree(djs, this );
1338: names.put(PdfName.JAVASCRIPT, addToBody(tree)
1339: .getIndirectReference());
1340: }
1341:
1342: void addFileAttachments() throws IOException {
1343: HashMap fs = pdf.getDocumentFileAttachment();
1344: if (fs.isEmpty())
1345: return;
1346: PdfDictionary catalog = reader.getCatalog();
1347: PdfDictionary names = (PdfDictionary) PdfReader.getPdfObject(
1348: catalog.get(PdfName.NAMES), catalog);
1349: if (names == null) {
1350: names = new PdfDictionary();
1351: catalog.put(PdfName.NAMES, names);
1352: markUsed(catalog);
1353: }
1354: markUsed(names);
1355: HashMap old = PdfNameTree.readTree((PdfDictionary) PdfReader
1356: .getPdfObjectRelease(names.get(PdfName.EMBEDDEDFILES)));
1357: for (Iterator it = fs.entrySet().iterator(); it.hasNext();) {
1358: Map.Entry entry = (Map.Entry) it.next();
1359: String name = (String) entry.getKey();
1360: int k = 0;
1361: String nn = name;
1362: while (old.containsKey(nn)) {
1363: ++k;
1364: nn += " " + k;
1365: }
1366: old.put(nn, entry.getValue());
1367: }
1368: PdfDictionary tree = PdfNameTree.writeTree(old, this );
1369: names.put(PdfName.EMBEDDEDFILES, addToBody(tree)
1370: .getIndirectReference());
1371: }
1372:
1373: /**
1374: * Adds or replaces the Collection Dictionary in the Catalog.
1375: * @param collection the new collection dictionary.
1376: */
1377: void makePackage(PdfCollection collection) {
1378: PdfDictionary catalog = reader.getCatalog();
1379: catalog.put(PdfName.COLLECTION, collection);
1380: }
1381:
1382: void setOutlines() throws IOException {
1383: if (newBookmarks == null)
1384: return;
1385: deleteOutlines();
1386: if (newBookmarks.isEmpty())
1387: return;
1388: PdfDictionary catalog = reader.getCatalog();
1389: boolean namedAsNames = (catalog.get(PdfName.DESTS) != null);
1390: writeOutlines(catalog, namedAsNames);
1391: markUsed(catalog);
1392: }
1393:
1394: /**
1395: * Sets the viewer preferences.
1396: * @param preferences the viewer preferences
1397: * @see PdfWriter#setViewerPreferences(int)
1398: */
1399: public void setViewerPreferences(int preferences) {
1400: useVp = true;
1401: this .viewerPreferences.setViewerPreferences(preferences);
1402: }
1403:
1404: /** Adds a viewer preference
1405: * @param key a key for a viewer preference
1406: * @param value the value for the viewer preference
1407: * @see PdfViewerPreferences#addViewerPreference
1408: */
1409: public void addViewerPreference(PdfName key, PdfObject value) {
1410: useVp = true;
1411: this .viewerPreferences.addViewerPreference(key, value);
1412: }
1413:
1414: /**
1415: * Set the signature flags.
1416: * @param f the flags. This flags are ORed with current ones
1417: */
1418: public void setSigFlags(int f) {
1419: sigFlags |= f;
1420: }
1421:
1422: /** Always throws an <code>UnsupportedOperationException</code>.
1423: * @param actionType ignore
1424: * @param action ignore
1425: * @throws PdfException ignore
1426: * @see PdfStamper#setPageAction(PdfName, PdfAction, int)
1427: */
1428: public void setPageAction(PdfName actionType, PdfAction action)
1429: throws PdfException {
1430: throw new UnsupportedOperationException(
1431: "Use setPageAction(PdfName actionType, PdfAction action, int page)");
1432: }
1433:
1434: /**
1435: * Sets the open and close page additional action.
1436: * @param actionType the action type. It can be <CODE>PdfWriter.PAGE_OPEN</CODE>
1437: * or <CODE>PdfWriter.PAGE_CLOSE</CODE>
1438: * @param action the action to perform
1439: * @param page the page where the action will be applied. The first page is 1
1440: * @throws PdfException if the action type is invalid
1441: */
1442: void setPageAction(PdfName actionType, PdfAction action, int page)
1443: throws PdfException {
1444: if (!actionType.equals(PAGE_OPEN)
1445: && !actionType.equals(PAGE_CLOSE))
1446: throw new PdfException(
1447: "Invalid page additional action type: "
1448: + actionType.toString());
1449: PdfDictionary pg = reader.getPageN(page);
1450: PdfDictionary aa = (PdfDictionary) PdfReader.getPdfObject(pg
1451: .get(PdfName.AA), pg);
1452: if (aa == null) {
1453: aa = new PdfDictionary();
1454: pg.put(PdfName.AA, aa);
1455: markUsed(pg);
1456: }
1457: aa.put(actionType, action);
1458: markUsed(aa);
1459: }
1460:
1461: /**
1462: * Always throws an <code>UnsupportedOperationException</code>.
1463: * @param seconds ignore
1464: */
1465: public void setDuration(int seconds) {
1466: throw new UnsupportedOperationException(
1467: "Use setPageAction(PdfName actionType, PdfAction action, int page)");
1468: }
1469:
1470: /**
1471: * Always throws an <code>UnsupportedOperationException</code>.
1472: * @param transition ignore
1473: */
1474: public void setTransition(PdfTransition transition) {
1475: throw new UnsupportedOperationException(
1476: "Use setPageAction(PdfName actionType, PdfAction action, int page)");
1477: }
1478:
1479: /**
1480: * Sets the display duration for the page (for presentations)
1481: * @param seconds the number of seconds to display the page. A negative value removes the entry
1482: * @param page the page where the duration will be applied. The first page is 1
1483: */
1484: void setDuration(int seconds, int page) {
1485: PdfDictionary pg = reader.getPageN(page);
1486: if (seconds < 0)
1487: pg.remove(PdfName.DUR);
1488: else
1489: pg.put(PdfName.DUR, new PdfNumber(seconds));
1490: markUsed(pg);
1491: }
1492:
1493: /**
1494: * Sets the transition for the page
1495: * @param transition the transition object. A <code>null</code> removes the transition
1496: * @param page the page where the transition will be applied. The first page is 1
1497: */
1498: void setTransition(PdfTransition transition, int page) {
1499: PdfDictionary pg = reader.getPageN(page);
1500: if (transition == null)
1501: pg.remove(PdfName.TRANS);
1502: else
1503: pg.put(PdfName.TRANS, transition.getTransitionDictionary());
1504: markUsed(pg);
1505: }
1506:
1507: protected void markUsed(PdfObject obj) {
1508: if (append && obj != null) {
1509: PRIndirectReference ref = null;
1510: if (obj.type() == PdfObject.INDIRECT)
1511: ref = (PRIndirectReference) obj;
1512: else
1513: ref = obj.getIndRef();
1514: if (ref != null)
1515: marked.put(ref.getNumber(), 1);
1516: }
1517: }
1518:
1519: protected void markUsed(int num) {
1520: if (append)
1521: marked.put(num, 1);
1522: }
1523:
1524: /**
1525: * Getter for property append.
1526: * @return Value of property append.
1527: */
1528: boolean isAppend() {
1529: return append;
1530: }
1531:
1532: /** Additional-actions defining the actions to be taken in
1533: * response to various trigger events affecting the document
1534: * as a whole. The actions types allowed are: <CODE>DOCUMENT_CLOSE</CODE>,
1535: * <CODE>WILL_SAVE</CODE>, <CODE>DID_SAVE</CODE>, <CODE>WILL_PRINT</CODE>
1536: * and <CODE>DID_PRINT</CODE>.
1537: *
1538: * @param actionType the action type
1539: * @param action the action to execute in response to the trigger
1540: * @throws PdfException on invalid action type
1541: */
1542: public void setAdditionalAction(PdfName actionType, PdfAction action)
1543: throws PdfException {
1544: if (!(actionType.equals(DOCUMENT_CLOSE)
1545: || actionType.equals(WILL_SAVE)
1546: || actionType.equals(DID_SAVE)
1547: || actionType.equals(WILL_PRINT) || actionType
1548: .equals(DID_PRINT))) {
1549: throw new PdfException("Invalid additional action type: "
1550: + actionType.toString());
1551: }
1552: PdfDictionary aa = (PdfDictionary) PdfReader
1553: .getPdfObject(reader.getCatalog().get(PdfName.AA));
1554: if (aa == null) {
1555: if (action == null)
1556: return;
1557: aa = new PdfDictionary();
1558: reader.getCatalog().put(PdfName.AA, aa);
1559: }
1560: markUsed(aa);
1561: if (action == null)
1562: aa.remove(actionType);
1563: else
1564: aa.put(actionType, action);
1565: }
1566:
1567: /**
1568: * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(com.lowagie.text.pdf.PdfAction)
1569: */
1570: public void setOpenAction(PdfAction action) {
1571: openAction = action;
1572: }
1573:
1574: /**
1575: * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(java.lang.String)
1576: */
1577: public void setOpenAction(String name) {
1578: throw new UnsupportedOperationException(
1579: "Open actions by name are not supported.");
1580: }
1581:
1582: /**
1583: * @see com.lowagie.text.pdf.PdfWriter#setThumbnail(com.lowagie.text.Image)
1584: */
1585: public void setThumbnail(com.lowagie.text.Image image) {
1586: throw new UnsupportedOperationException(
1587: "Use PdfStamper.setThumbnail().");
1588: }
1589:
1590: void setThumbnail(Image image, int page) throws PdfException,
1591: DocumentException {
1592: PdfIndirectReference thumb = getImageReference(addDirectImageSimple(image));
1593: reader.resetReleasePage();
1594: PdfDictionary dic = reader.getPageN(page);
1595: dic.put(PdfName.THUMB, thumb);
1596: reader.resetReleasePage();
1597: }
1598:
1599: public PdfContentByte getDirectContentUnder() {
1600: throw new UnsupportedOperationException(
1601: "Use PdfStamper.getUnderContent() or PdfStamper.getOverContent()");
1602: }
1603:
1604: public PdfContentByte getDirectContent() {
1605: throw new UnsupportedOperationException(
1606: "Use PdfStamper.getUnderContent() or PdfStamper.getOverContent()");
1607: }
1608:
1609: static class PageStamp {
1610:
1611: PdfDictionary pageN;
1612: StampContent under;
1613: StampContent over;
1614: PageResources pageResources;
1615:
1616: PageStamp(PdfStamperImp stamper, PdfReader reader,
1617: PdfDictionary pageN) {
1618: this .pageN = pageN;
1619: pageResources = new PageResources();
1620: PdfDictionary resources = (PdfDictionary) PdfReader
1621: .getPdfObject(pageN.get(PdfName.RESOURCES));
1622: pageResources.setOriginalResources(resources,
1623: stamper.namePtr);
1624: }
1625: }
1626: }
|