001: /*
002: * $Id: PdfCopy.java 2907 2007-08-31 11:24:47Z blowagie $
003: * $Name$
004: *
005: * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
022: *
023: * This module by Mark Thompson. Copyright (C) 2002 Mark Thompson
024: *
025: * Contributor(s): all the names of the contributors are added in the source code
026: * where applicable.
027: *
028: * Alternatively, the contents of this file may be used under the terms of the
029: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
030: * provisions of LGPL are applicable instead of those above. If you wish to
031: * allow use of your version of this file only under the terms of the LGPL
032: * License and not to allow others to use your version of this file under
033: * the MPL, indicate your decision by deleting the provisions above and
034: * replace them with the notice and other provisions required by the LGPL.
035: * If you do not delete the provisions above, a recipient may use your version
036: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
037: *
038: * This library is free software; you can redistribute it and/or modify it
039: * under the terms of the MPL as stated above or under the terms of the GNU
040: * Library General Public License as published by the Free Software Foundation;
041: * either version 2 of the License, or any later version.
042: *
043: * This library is distributed in the hope that it will be useful, but WITHOUT
044: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
045: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
046: * details.
047: *
048: * If you didn't download this code from the following link, you should check if
049: * you aren't using an obsolete version:
050: * http://www.lowagie.com/iText/
051: */
052: package com.lowagie.text.pdf;
053:
054: import java.io.IOException;
055: import java.io.OutputStream;
056: import java.util.HashMap;
057: import java.util.Iterator;
058:
059: import com.lowagie.text.Document;
060: import com.lowagie.text.DocumentException;
061: import com.lowagie.text.ExceptionConverter;
062: import com.lowagie.text.Rectangle;
063: import java.util.ArrayList;
064:
065: /**
066: * Make copies of PDF documents. Documents can be edited after reading and
067: * before writing them out.
068: * @author Mark Thompson
069: */
070:
071: public class PdfCopy extends PdfWriter {
072: /**
073: * This class holds information about indirect references, since they are
074: * renumbered by iText.
075: */
076: static class IndirectReferences {
077: PdfIndirectReference theRef;
078: boolean hasCopied;
079:
080: IndirectReferences(PdfIndirectReference ref) {
081: theRef = ref;
082: hasCopied = false;
083: }
084:
085: void setCopied() {
086: hasCopied = true;
087: }
088:
089: boolean getCopied() {
090: return hasCopied;
091: }
092:
093: PdfIndirectReference getRef() {
094: return theRef;
095: }
096: };
097:
098: protected HashMap indirects;
099: protected HashMap indirectMap;
100: protected int currentObjectNum = 1;
101: protected PdfReader reader;
102: protected PdfIndirectReference acroForm;
103: protected int[] namePtr = { 0 };
104: /** Holds value of property rotateContents. */
105: private boolean rotateContents = true;
106: protected PdfArray fieldArray;
107: protected HashMap fieldTemplates;
108:
109: /**
110: * A key to allow us to hash indirect references
111: */
112: protected static class RefKey {
113: int num;
114: int gen;
115:
116: RefKey(int num, int gen) {
117: this .num = num;
118: this .gen = gen;
119: }
120:
121: RefKey(PdfIndirectReference ref) {
122: num = ref.getNumber();
123: gen = ref.getGeneration();
124: }
125:
126: RefKey(PRIndirectReference ref) {
127: num = ref.getNumber();
128: gen = ref.getGeneration();
129: }
130:
131: public int hashCode() {
132: return (gen << 16) + num;
133: }
134:
135: public boolean equals(Object o) {
136: if (!(o instanceof RefKey))
137: return false;
138: RefKey other = (RefKey) o;
139: return this .gen == other.gen && this .num == other.num;
140: }
141:
142: public String toString() {
143: return Integer.toString(num) + ' ' + gen;
144: }
145: }
146:
147: /**
148: * Constructor
149: * @param document
150: * @param os outputstream
151: */
152: public PdfCopy(Document document, OutputStream os)
153: throws DocumentException {
154: super (new PdfDocument(), os);
155: document.addDocListener(pdf);
156: pdf.addWriter(this );
157: indirectMap = new HashMap();
158: }
159:
160: /** Getter for property rotateContents.
161: * @return Value of property rotateContents.
162: *
163: */
164: public boolean isRotateContents() {
165: return this .rotateContents;
166: }
167:
168: /** Setter for property rotateContents.
169: * @param rotateContents New value of property rotateContents.
170: *
171: */
172: public void setRotateContents(boolean rotateContents) {
173: this .rotateContents = rotateContents;
174: }
175:
176: /**
177: * Grabs a page from the input document
178: * @param reader the reader of the document
179: * @param pageNumber which page to get
180: * @return the page
181: */
182: public PdfImportedPage getImportedPage(PdfReader reader,
183: int pageNumber) {
184: if (currentPdfReaderInstance != null) {
185: if (currentPdfReaderInstance.getReader() != reader) {
186: try {
187: currentPdfReaderInstance.getReader().close();
188: currentPdfReaderInstance.getReaderFile().close();
189: } catch (IOException ioe) {
190: // empty on purpose
191: }
192: currentPdfReaderInstance = reader
193: .getPdfReaderInstance(this );
194: }
195: } else {
196: currentPdfReaderInstance = reader
197: .getPdfReaderInstance(this );
198: }
199: return currentPdfReaderInstance.getImportedPage(pageNumber);
200: }
201:
202: /**
203: * Translate a PRIndirectReference to a PdfIndirectReference
204: * In addition, translates the object numbers, and copies the
205: * referenced object to the output file.
206: * NB: PRIndirectReferences (and PRIndirectObjects) really need to know what
207: * file they came from, because each file has its own namespace. The translation
208: * we do from their namespace to ours is *at best* heuristic, and guaranteed to
209: * fail under some circumstances.
210: */
211: protected PdfIndirectReference copyIndirect(PRIndirectReference in)
212: throws IOException, BadPdfFormatException {
213: PdfIndirectReference theRef;
214: RefKey key = new RefKey(in);
215: IndirectReferences iRef = (IndirectReferences) indirects
216: .get(key);
217: if (iRef != null) {
218: theRef = iRef.getRef();
219: if (iRef.getCopied()) {
220: return theRef;
221: }
222: } else {
223: theRef = body.getPdfIndirectReference();
224: iRef = new IndirectReferences(theRef);
225: indirects.put(key, iRef);
226: }
227: PdfObject obj = PdfReader.getPdfObjectRelease(in);
228: if (obj != null && obj.isDictionary()) {
229: PdfObject type = PdfReader
230: .getPdfObjectRelease(((PdfDictionary) obj)
231: .get(PdfName.TYPE));
232: if (type != null && PdfName.PAGE.equals(type)) {
233: return theRef;
234: }
235: }
236: iRef.setCopied();
237: obj = copyObject(obj);
238: addToBody(obj, theRef);
239: return theRef;
240: }
241:
242: /**
243: * Translate a PRDictionary to a PdfDictionary. Also translate all of the
244: * objects contained in it.
245: */
246: protected PdfDictionary copyDictionary(PdfDictionary in)
247: throws IOException, BadPdfFormatException {
248: PdfDictionary out = new PdfDictionary();
249: PdfObject type = PdfReader.getPdfObjectRelease(in
250: .get(PdfName.TYPE));
251:
252: for (Iterator it = in.getKeys().iterator(); it.hasNext();) {
253: PdfName key = (PdfName) it.next();
254: PdfObject value = in.get(key);
255: // System.out.println("Copy " + key);
256: if (type != null && PdfName.PAGE.equals(type)) {
257: if (!key.equals(PdfName.B)
258: && !key.equals(PdfName.PARENT))
259: out.put(key, copyObject(value));
260: } else
261: out.put(key, copyObject(value));
262: }
263: return out;
264: }
265:
266: /**
267: * Translate a PRStream to a PdfStream. The data part copies itself.
268: */
269: protected PdfStream copyStream(PRStream in) throws IOException,
270: BadPdfFormatException {
271: PRStream out = new PRStream(in, null);
272:
273: for (Iterator it = in.getKeys().iterator(); it.hasNext();) {
274: PdfName key = (PdfName) it.next();
275: PdfObject value = in.get(key);
276: out.put(key, copyObject(value));
277: }
278:
279: return out;
280: }
281:
282: /**
283: * Translate a PRArray to a PdfArray. Also translate all of the objects contained
284: * in it
285: */
286: protected PdfArray copyArray(PdfArray in) throws IOException,
287: BadPdfFormatException {
288: PdfArray out = new PdfArray();
289:
290: for (Iterator i = in.getArrayList().iterator(); i.hasNext();) {
291: PdfObject value = (PdfObject) i.next();
292: out.add(copyObject(value));
293: }
294: return out;
295: }
296:
297: /**
298: * Translate a PR-object to a Pdf-object
299: */
300: protected PdfObject copyObject(PdfObject in) throws IOException,
301: BadPdfFormatException {
302: if (in == null)
303: return PdfNull.PDFNULL;
304: switch (in.type) {
305: case PdfObject.DICTIONARY:
306: // System.out.println("Dictionary: " + in.toString());
307: return copyDictionary((PdfDictionary) in);
308: case PdfObject.INDIRECT:
309: return copyIndirect((PRIndirectReference) in);
310: case PdfObject.ARRAY:
311: return copyArray((PdfArray) in);
312: case PdfObject.NUMBER:
313: case PdfObject.NAME:
314: case PdfObject.STRING:
315: case PdfObject.NULL:
316: case PdfObject.BOOLEAN:
317: case 0:
318: return in;
319: case PdfObject.STREAM:
320: return copyStream((PRStream) in);
321: // return in;
322: default:
323: if (in.type < 0) {
324: String lit = ((PdfLiteral) in).toString();
325: if (lit.equals("true") || lit.equals("false")) {
326: return new PdfBoolean(lit);
327: }
328: return new PdfLiteral(lit);
329: }
330: System.out.println("CANNOT COPY type " + in.type);
331: return null;
332: }
333: }
334:
335: /**
336: * convenience method. Given an importedpage, set our "globals"
337: */
338: protected int setFromIPage(PdfImportedPage iPage) {
339: int pageNum = iPage.getPageNumber();
340: PdfReaderInstance inst = currentPdfReaderInstance = iPage
341: .getPdfReaderInstance();
342: reader = inst.getReader();
343: setFromReader(reader);
344: return pageNum;
345: }
346:
347: /**
348: * convenience method. Given a reader, set our "globals"
349: */
350: protected void setFromReader(PdfReader reader) {
351: this .reader = reader;
352: indirects = (HashMap) indirectMap.get(reader);
353: if (indirects == null) {
354: indirects = new HashMap();
355: indirectMap.put(reader, indirects);
356: PdfDictionary catalog = reader.getCatalog();
357: PRIndirectReference ref = null;
358: PdfObject o = catalog.get(PdfName.ACROFORM);
359: if (o == null || o.type() != PdfObject.INDIRECT)
360: return;
361: ref = (PRIndirectReference) o;
362: if (acroForm == null)
363: acroForm = body.getPdfIndirectReference();
364: indirects.put(new RefKey(ref), new IndirectReferences(
365: acroForm));
366: }
367: }
368:
369: /**
370: * Add an imported page to our output
371: * @param iPage an imported page
372: * @throws IOException, BadPdfFormatException
373: */
374: public void addPage(PdfImportedPage iPage) throws IOException,
375: BadPdfFormatException {
376: int pageNum = setFromIPage(iPage);
377:
378: PdfDictionary thePage = reader.getPageN(pageNum);
379: PRIndirectReference origRef = reader.getPageOrigRef(pageNum);
380: reader.releasePage(pageNum);
381: RefKey key = new RefKey(origRef);
382: PdfIndirectReference pageRef;
383: IndirectReferences iRef = (IndirectReferences) indirects
384: .get(key);
385: if (iRef != null && !iRef.getCopied()) {
386: pageReferences.add(iRef.getRef());
387: iRef.setCopied();
388: }
389: pageRef = getCurrentPage();
390: if (iRef == null) {
391: iRef = new IndirectReferences(pageRef);
392: indirects.put(key, iRef);
393: }
394: iRef.setCopied();
395: PdfDictionary newPage = copyDictionary(thePage);
396: root.addPage(newPage);
397: ++currentPageNumber;
398: }
399:
400: /**
401: * Copy the acroform for an input document. Note that you can only have one,
402: * we make no effort to merge them.
403: * @param reader The reader of the input file that is being copied
404: * @throws IOException, BadPdfFormatException
405: */
406: public void copyAcroForm(PdfReader reader) throws IOException,
407: BadPdfFormatException {
408: setFromReader(reader);
409:
410: PdfDictionary catalog = reader.getCatalog();
411: PRIndirectReference hisRef = null;
412: PdfObject o = catalog.get(PdfName.ACROFORM);
413: if (o != null && o.type() == PdfObject.INDIRECT)
414: hisRef = (PRIndirectReference) o;
415: if (hisRef == null)
416: return; // bugfix by John Englar
417: RefKey key = new RefKey(hisRef);
418: PdfIndirectReference myRef;
419: IndirectReferences iRef = (IndirectReferences) indirects
420: .get(key);
421: if (iRef != null) {
422: acroForm = myRef = iRef.getRef();
423: } else {
424: acroForm = myRef = body.getPdfIndirectReference();
425: iRef = new IndirectReferences(myRef);
426: indirects.put(key, iRef);
427: }
428: if (!iRef.getCopied()) {
429: iRef.setCopied();
430: PdfDictionary theForm = copyDictionary((PdfDictionary) PdfReader
431: .getPdfObject(hisRef));
432: addToBody(theForm, myRef);
433: }
434: }
435:
436: /*
437: * the getCatalog method is part of PdfWriter.
438: * we wrap this so that we can extend it
439: */
440: protected PdfDictionary getCatalog(PdfIndirectReference rootObj) {
441: try {
442: PdfDictionary theCat = pdf.getCatalog(rootObj);
443: if (fieldArray == null) {
444: if (acroForm != null)
445: theCat.put(PdfName.ACROFORM, acroForm);
446: } else
447: addFieldResources(theCat);
448: writeOutlines(theCat, false);
449: return theCat;
450: } catch (IOException e) {
451: throw new ExceptionConverter(e);
452: }
453: }
454:
455: private void addFieldResources(PdfDictionary catalog)
456: throws IOException {
457: if (fieldArray == null)
458: return;
459: PdfDictionary acroForm = new PdfDictionary();
460: catalog.put(PdfName.ACROFORM, acroForm);
461: acroForm.put(PdfName.FIELDS, fieldArray);
462: acroForm.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g "));
463: if (fieldTemplates.isEmpty())
464: return;
465: PdfDictionary dr = new PdfDictionary();
466: acroForm.put(PdfName.DR, dr);
467: for (Iterator it = fieldTemplates.keySet().iterator(); it
468: .hasNext();) {
469: PdfTemplate template = (PdfTemplate) it.next();
470: PdfFormField.mergeResources(dr, (PdfDictionary) template
471: .getResources());
472: }
473: if (dr.get(PdfName.ENCODING) == null)
474: dr.put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING);
475: PdfDictionary fonts = (PdfDictionary) PdfReader.getPdfObject(dr
476: .get(PdfName.FONT));
477: if (fonts == null) {
478: fonts = new PdfDictionary();
479: dr.put(PdfName.FONT, fonts);
480: }
481: if (!fonts.contains(PdfName.HELV)) {
482: PdfDictionary dic = new PdfDictionary(PdfName.FONT);
483: dic.put(PdfName.BASEFONT, PdfName.HELVETICA);
484: dic.put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING);
485: dic.put(PdfName.NAME, PdfName.HELV);
486: dic.put(PdfName.SUBTYPE, PdfName.TYPE1);
487: fonts.put(PdfName.HELV, addToBody(dic)
488: .getIndirectReference());
489: }
490: if (!fonts.contains(PdfName.ZADB)) {
491: PdfDictionary dic = new PdfDictionary(PdfName.FONT);
492: dic.put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS);
493: dic.put(PdfName.NAME, PdfName.ZADB);
494: dic.put(PdfName.SUBTYPE, PdfName.TYPE1);
495: fonts.put(PdfName.ZADB, addToBody(dic)
496: .getIndirectReference());
497: }
498: }
499:
500: /**
501: * Signals that the <CODE>Document</CODE> was closed and that no other
502: * <CODE>Elements</CODE> will be added.
503: * <P>
504: * The pages-tree is built and written to the outputstream.
505: * A Catalog is constructed, as well as an Info-object,
506: * the referencetable is composed and everything is written
507: * to the outputstream embedded in a Trailer.
508: */
509:
510: public void close() {
511: if (open) {
512: PdfReaderInstance ri = currentPdfReaderInstance;
513: pdf.close();
514: super .close();
515: if (ri != null) {
516: try {
517: ri.getReader().close();
518: ri.getReaderFile().close();
519: } catch (IOException ioe) {
520: // empty on purpose
521: }
522: }
523: }
524: }
525:
526: public PdfIndirectReference add(PdfOutline outline) {
527: return null;
528: }
529:
530: public void addAnnotation(PdfAnnotation annot) {
531: }
532:
533: PdfIndirectReference add(PdfPage page, PdfContents contents)
534: throws PdfException {
535: return null;
536: }
537:
538: public void freeReader(PdfReader reader) throws IOException {
539: indirectMap.remove(reader);
540: if (currentPdfReaderInstance != null) {
541: if (currentPdfReaderInstance.getReader() == reader) {
542: try {
543: currentPdfReaderInstance.getReader().close();
544: currentPdfReaderInstance.getReaderFile().close();
545: } catch (IOException ioe) {
546: // empty on purpose
547: }
548: currentPdfReaderInstance = null;
549: }
550: }
551: }
552:
553: /**
554: * Create a page stamp. New content and annotations, including new fields, are allowed.
555: * The fields added cannot have parents in another pages. This method modifies the PdfReader instance.<p>
556: * The general usage to stamp something in a page is:
557: * <p>
558: * <pre>
559: * PdfImportedPage page = copy.getImportedPage(reader, 1);
560: * PdfCopy.PageStamp ps = copy.createPageStamp(page);
561: * ps.addAnnotation(PdfAnnotation.createText(copy, new Rectangle(50, 180, 70, 200), "Hello", "No Thanks", true, "Comment"));
562: * PdfContentByte under = ps.getUnderContent();
563: * under.addImage(img);
564: * PdfContentByte over = ps.getOverContent();
565: * over.beginText();
566: * over.setFontAndSize(bf, 18);
567: * over.setTextMatrix(30, 30);
568: * over.showText("total page " + totalPage);
569: * over.endText();
570: * ps.alterContents();
571: * copy.addPage(page);
572: * </pre>
573: * @param iPage an imported page
574: * @return the <CODE>PageStamp</CODE>
575: */
576: public PageStamp createPageStamp(PdfImportedPage iPage) {
577: int pageNum = iPage.getPageNumber();
578: PdfReader reader = iPage.getPdfReaderInstance().getReader();
579: PdfDictionary pageN = reader.getPageN(pageNum);
580: return new PageStamp(reader, pageN, this );
581: }
582:
583: public static class PageStamp {
584:
585: PdfDictionary pageN;
586: PdfCopy.StampContent under;
587: PdfCopy.StampContent over;
588: PageResources pageResources;
589: PdfReader reader;
590: PdfCopy cstp;
591:
592: PageStamp(PdfReader reader, PdfDictionary pageN, PdfCopy cstp) {
593: this .pageN = pageN;
594: this .reader = reader;
595: this .cstp = cstp;
596: }
597:
598: public PdfContentByte getUnderContent() {
599: if (under == null) {
600: if (pageResources == null) {
601: pageResources = new PageResources();
602: PdfDictionary resources = (PdfDictionary) PdfReader
603: .getPdfObject(pageN.get(PdfName.RESOURCES));
604: pageResources.setOriginalResources(resources,
605: cstp.namePtr);
606: }
607: under = new PdfCopy.StampContent(cstp, pageResources);
608: }
609: return under;
610: }
611:
612: public PdfContentByte getOverContent() {
613: if (over == null) {
614: if (pageResources == null) {
615: pageResources = new PageResources();
616: PdfDictionary resources = (PdfDictionary) PdfReader
617: .getPdfObject(pageN.get(PdfName.RESOURCES));
618: pageResources.setOriginalResources(resources,
619: cstp.namePtr);
620: }
621: over = new PdfCopy.StampContent(cstp, pageResources);
622: }
623: return over;
624: }
625:
626: public void alterContents() throws IOException {
627: if (over == null && under == null)
628: return;
629: PdfArray ar = null;
630: PdfObject content = PdfReader.getPdfObject(pageN
631: .get(PdfName.CONTENTS), pageN);
632: if (content == null) {
633: ar = new PdfArray();
634: pageN.put(PdfName.CONTENTS, ar);
635: } else if (content.isArray()) {
636: ar = (PdfArray) content;
637: } else if (content.isStream()) {
638: ar = new PdfArray();
639: ar.add(pageN.get(PdfName.CONTENTS));
640: pageN.put(PdfName.CONTENTS, ar);
641: } else {
642: ar = new PdfArray();
643: pageN.put(PdfName.CONTENTS, ar);
644: }
645: ByteBuffer out = new ByteBuffer();
646: if (under != null) {
647: out.append(PdfContents.SAVESTATE);
648: applyRotation(pageN, out);
649: out.append(under.getInternalBuffer());
650: out.append(PdfContents.RESTORESTATE);
651: }
652: if (over != null)
653: out.append(PdfContents.SAVESTATE);
654: PdfStream stream = new PdfStream(out.toByteArray());
655: stream.flateCompress();
656: PdfIndirectReference ref1 = cstp.addToBody(stream)
657: .getIndirectReference();
658: ar.addFirst(ref1);
659: out.reset();
660: if (over != null) {
661: out.append(' ');
662: out.append(PdfContents.RESTORESTATE);
663: out.append(PdfContents.SAVESTATE);
664: applyRotation(pageN, out);
665: out.append(over.getInternalBuffer());
666: out.append(PdfContents.RESTORESTATE);
667: stream = new PdfStream(out.toByteArray());
668: stream.flateCompress();
669: ar.add(cstp.addToBody(stream).getIndirectReference());
670: }
671: pageN.put(PdfName.RESOURCES, pageResources.getResources());
672: }
673:
674: void applyRotation(PdfDictionary pageN, ByteBuffer out) {
675: if (!cstp.rotateContents)
676: return;
677: Rectangle page = reader.getPageSizeWithRotation(pageN);
678: int rotation = page.getRotation();
679: switch (rotation) {
680: case 90:
681: out.append(PdfContents.ROTATE90);
682: out.append(page.getTop());
683: out.append(' ').append('0').append(
684: PdfContents.ROTATEFINAL);
685: break;
686: case 180:
687: out.append(PdfContents.ROTATE180);
688: out.append(page.getRight());
689: out.append(' ');
690: out.append(page.getTop());
691: out.append(PdfContents.ROTATEFINAL);
692: break;
693: case 270:
694: out.append(PdfContents.ROTATE270);
695: out.append('0').append(' ');
696: out.append(page.getRight());
697: out.append(PdfContents.ROTATEFINAL);
698: break;
699: }
700: }
701:
702: private void addDocumentField(PdfIndirectReference ref) {
703: if (cstp.fieldArray == null)
704: cstp.fieldArray = new PdfArray();
705: cstp.fieldArray.add(ref);
706: }
707:
708: private void expandFields(PdfFormField field,
709: ArrayList allAnnots) {
710: allAnnots.add(field);
711: ArrayList kids = field.getKids();
712: if (kids != null) {
713: for (int k = 0; k < kids.size(); ++k)
714: expandFields((PdfFormField) kids.get(k), allAnnots);
715: }
716: }
717:
718: public void addAnnotation(PdfAnnotation annot) {
719: try {
720: ArrayList allAnnots = new ArrayList();
721: if (annot.isForm()) {
722: PdfFormField field = (PdfFormField) annot;
723: if (field.getParent() != null)
724: return;
725: expandFields(field, allAnnots);
726: if (cstp.fieldTemplates == null)
727: cstp.fieldTemplates = new HashMap();
728: } else
729: allAnnots.add(annot);
730: for (int k = 0; k < allAnnots.size(); ++k) {
731: annot = (PdfAnnotation) allAnnots.get(k);
732: if (annot.isForm()) {
733: if (!annot.isUsed()) {
734: HashMap templates = annot.getTemplates();
735: if (templates != null)
736: cstp.fieldTemplates.putAll(templates);
737: }
738: PdfFormField field = (PdfFormField) annot;
739: if (field.getParent() == null)
740: addDocumentField(field
741: .getIndirectReference());
742: }
743: if (annot.isAnnotation()) {
744: PdfObject pdfobj = PdfReader.getPdfObject(pageN
745: .get(PdfName.ANNOTS), pageN);
746: PdfArray annots = null;
747: if (pdfobj == null || !pdfobj.isArray()) {
748: annots = new PdfArray();
749: pageN.put(PdfName.ANNOTS, annots);
750: } else
751: annots = (PdfArray) pdfobj;
752: annots.add(annot.getIndirectReference());
753: if (!annot.isUsed()) {
754: PdfRectangle rect = (PdfRectangle) annot
755: .get(PdfName.RECT);
756: if (rect != null
757: && (rect.left() != 0
758: || rect.right() != 0
759: || rect.top() != 0 || rect
760: .bottom() != 0)) {
761: int rotation = reader
762: .getPageRotation(pageN);
763: Rectangle pageSize = reader
764: .getPageSizeWithRotation(pageN);
765: switch (rotation) {
766: case 90:
767: annot
768: .put(
769: PdfName.RECT,
770: new PdfRectangle(
771: pageSize
772: .getTop()
773: - rect
774: .bottom(),
775: rect.left(),
776: pageSize
777: .getTop()
778: - rect
779: .top(),
780: rect
781: .right()));
782: break;
783: case 180:
784: annot
785: .put(
786: PdfName.RECT,
787: new PdfRectangle(
788: pageSize
789: .getRight()
790: - rect
791: .left(),
792: pageSize
793: .getTop()
794: - rect
795: .bottom(),
796: pageSize
797: .getRight()
798: - rect
799: .right(),
800: pageSize
801: .getTop()
802: - rect
803: .top()));
804: break;
805: case 270:
806: annot.put(PdfName.RECT,
807: new PdfRectangle(rect
808: .bottom(), pageSize
809: .getRight()
810: - rect.left(), rect
811: .top(), pageSize
812: .getRight()
813: - rect.right()));
814: break;
815: }
816: }
817: }
818: }
819: if (!annot.isUsed()) {
820: annot.setUsed();
821: cstp.addToBody(annot, annot
822: .getIndirectReference());
823: }
824: }
825: } catch (IOException e) {
826: throw new ExceptionConverter(e);
827: }
828: }
829: }
830:
831: public static class StampContent extends PdfContentByte {
832: PageResources pageResources;
833:
834: /** Creates a new instance of StampContent */
835: StampContent(PdfWriter writer, PageResources pageResources) {
836: super (writer);
837: this .pageResources = pageResources;
838: }
839:
840: /**
841: * Gets a duplicate of this <CODE>PdfContentByte</CODE>. All
842: * the members are copied by reference but the buffer stays different.
843: *
844: * @return a copy of this <CODE>PdfContentByte</CODE>
845: */
846: public PdfContentByte getDuplicate() {
847: return new PdfCopy.StampContent(writer, pageResources);
848: }
849:
850: PageResources getPageResources() {
851: return pageResources;
852: }
853: }
854: }
|