KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > PdfStamper


1 /*
2  * Copyright 2003, 2004 by Paulo Soares.
3  *
4  * The contents of this file are subject to the Mozilla Public License Version 1.1
5  * (the "License"); you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the License.
11  *
12  * The Original Code is 'iText, a free JAVA-PDF library'.
13  *
14  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
15  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
16  * All Rights Reserved.
17  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
18  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
19  *
20  * Contributor(s): all the names of the contributors are added in the source code
21  * where applicable.
22  *
23  * Alternatively, the contents of this file may be used under the terms of the
24  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
25  * provisions of LGPL are applicable instead of those above. If you wish to
26  * allow use of your version of this file only under the terms of the LGPL
27  * License and not to allow others to use your version of this file under
28  * the MPL, indicate your decision by deleting the provisions above and
29  * replace them with the notice and other provisions required by the LGPL.
30  * If you do not delete the provisions above, a recipient may use your version
31  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
32  *
33  * This library is free software; you can redistribute it and/or modify it
34  * under the terms of the MPL as stated above or under the terms of the GNU
35  * Library General Public License as published by the Free Software Foundation;
36  * either version 2 of the License, or any later version.
37  *
38  * This library is distributed in the hope that it will be useful, but WITHOUT
39  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
40  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
41  * details.
42  *
43  * If you didn't download this code from the following link, you should check if
44  * you aren't using an obsolete version:
45  * http://www.lowagie.com/iText/
46  */

47 package com.lowagie.text.pdf;
48
49 import java.io.File JavaDoc;
50 import java.io.FileOutputStream JavaDoc;
51 import java.io.IOException JavaDoc;
52 import java.io.InputStream JavaDoc;
53 import java.io.OutputStream JavaDoc;
54 import java.security.SignatureException JavaDoc;
55 import java.util.HashMap JavaDoc;
56 import java.util.List JavaDoc;
57
58 import com.lowagie.text.DocWriter;
59 import com.lowagie.text.DocumentException;
60 import com.lowagie.text.ExceptionConverter;
61 import com.lowagie.text.Image;
62 import com.lowagie.text.Rectangle;
63 import com.lowagie.text.pdf.collection.PdfCollection;
64 import com.lowagie.text.pdf.interfaces.PdfEncryptionSettings;
65 import com.lowagie.text.pdf.interfaces.PdfViewerPreferences;
66 import java.security.cert.Certificate JavaDoc;
67
68 /** Applies extra content to the pages of a PDF document.
69  * This extra content can be all the objects allowed in PdfContentByte
70  * including pages from other Pdfs. The original PDF will keep
71  * all the interactive elements including bookmarks, links and form fields.
72  * <p>
73  * It is also possible to change the field values and to
74  * flatten them. New fields can be added but not flattened.
75  * @author Paulo Soares (psoares@consiste.pt)
76  */

77 public class PdfStamper
78     implements PdfViewerPreferences, PdfEncryptionSettings {
79     /**
80      * The writer
81      */

82     protected PdfStamperImp stamper;
83     private HashMap JavaDoc moreInfo;
84     private boolean hasSignature;
85     private PdfSignatureAppearance sigApp;
86
87     /** Starts the process of adding extra content to an existing PDF
88      * document.
89      * @param reader the original document. It cannot be reused
90      * @param os the output stream
91      * @throws DocumentException on error
92      * @throws IOException on error
93      */

94     public PdfStamper(PdfReader reader, OutputStream JavaDoc os) throws DocumentException, IOException JavaDoc {
95         stamper = new PdfStamperImp(reader, os, '\0', false);
96     }
97
98     /**
99      * Starts the process of adding extra content to an existing PDF
100      * document.
101      * @param reader the original document. It cannot be reused
102      * @param os the output stream
103      * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
104      * document
105      * @throws DocumentException on error
106      * @throws IOException on error
107      */

108     public PdfStamper(PdfReader reader, OutputStream JavaDoc os, char pdfVersion) throws DocumentException, IOException JavaDoc {
109         stamper = new PdfStamperImp(reader, os, pdfVersion, false);
110     }
111
112     /**
113      * Starts the process of adding extra content to an existing PDF
114      * document, possibly as a new revision.
115      * @param reader the original document. It cannot be reused
116      * @param os the output stream
117      * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
118      * document
119      * @param append if <CODE>true</CODE> appends the document changes as a new revision. This is
120      * only useful for multiple signatures as nothing is gained in speed or memory
121      * @throws DocumentException on error
122      * @throws IOException on error
123      */

124     public PdfStamper(PdfReader reader, OutputStream JavaDoc os, char pdfVersion, boolean append) throws DocumentException, IOException JavaDoc {
125         stamper = new PdfStamperImp(reader, os, pdfVersion, append);
126     }
127
128     /** Gets the optional <CODE>String</CODE> map to add or change values in
129      * the info dictionary.
130      * @return the map or <CODE>null</CODE>
131      *
132      */

133     public HashMap JavaDoc getMoreInfo() {
134         return this.moreInfo;
135     }
136
137     /** An optional <CODE>String</CODE> map to add or change values in
138      * the info dictionary. Entries with <CODE>null</CODE>
139      * values delete the key in the original info dictionary
140      * @param moreInfo additional entries to the info dictionary
141      *
142      */

143     public void setMoreInfo(HashMap JavaDoc moreInfo) {
144         this.moreInfo = moreInfo;
145     }
146
147     /**
148      * Inserts a blank page. All the pages above and including <CODE>pageNumber</CODE> will
149      * be shifted up. If <CODE>pageNumber</CODE> is bigger than the total number of pages
150      * the new page will be the last one.
151      * @param pageNumber the page number position where the new page will be inserted
152      * @param mediabox the size of the new page
153      */

154     public void insertPage(int pageNumber, Rectangle mediabox) {
155         stamper.insertPage(pageNumber, mediabox);
156     }
157     
158     /**
159      * Gets the signing instance. The appearances and other parameters can the be set.
160      * @return the signing instance
161      */

162     public PdfSignatureAppearance getSignatureAppearance() {
163         return sigApp;
164     }
165
166     /**
167      * Closes the document. No more content can be written after the
168      * document is closed.
169      * <p>
170      * If closing a signed document with an external signature the closing must be done
171      * in the <CODE>PdfSignatureAppearance</CODE> instance.
172      * @throws DocumentException on error
173      * @throws IOException on error
174      */

175     public void close() throws DocumentException, IOException JavaDoc {
176         if (!hasSignature) {
177             stamper.close(moreInfo);
178             return;
179         }
180         sigApp.preClose();
181         PdfSigGenericPKCS sig = sigApp.getSigStandard();
182         PdfLiteral lit = (PdfLiteral)sig.get(PdfName.CONTENTS);
183         int totalBuf = (lit.getPosLength() - 2) / 2;
184         byte buf[] = new byte[8192];
185         int n;
186         InputStream JavaDoc inp = sigApp.getRangeStream();
187         try {
188             while ((n = inp.read(buf)) > 0) {
189                 sig.getSigner().update(buf, 0, n);
190             }
191         }
192         catch (SignatureException JavaDoc se) {
193             throw new ExceptionConverter(se);
194         }
195         buf = new byte[totalBuf];
196         byte[] bsig = sig.getSignerContents();
197         System.arraycopy(bsig, 0, buf, 0, bsig.length);
198         PdfString str = new PdfString(buf);
199         str.setHexWriting(true);
200         PdfDictionary dic = new PdfDictionary();
201         dic.put(PdfName.CONTENTS, str);
202         sigApp.close(dic);
203         stamper.reader.close();
204     }
205
206     /** Gets a <CODE>PdfContentByte</CODE> to write under the page of
207      * the original document.
208      * @param pageNum the page number where the extra content is written
209      * @return a <CODE>PdfContentByte</CODE> to write under the page of
210      * the original document
211      */

212     public PdfContentByte getUnderContent(int pageNum) {
213         return stamper.getUnderContent(pageNum);
214     }
215
216     /** Gets a <CODE>PdfContentByte</CODE> to write over the page of
217      * the original document.
218      * @param pageNum the page number where the extra content is written
219      * @return a <CODE>PdfContentByte</CODE> to write over the page of
220      * the original document
221      */

222     public PdfContentByte getOverContent(int pageNum) {
223         return stamper.getOverContent(pageNum);
224     }
225
226     /** Checks if the content is automatically adjusted to compensate
227      * the original page rotation.
228      * @return the auto-rotation status
229      */

230     public boolean isRotateContents() {
231         return stamper.isRotateContents();
232     }
233
234     /** Flags the content to be automatically adjusted to compensate
235      * the original page rotation. The default is <CODE>true</CODE>.
236      * @param rotateContents <CODE>true</CODE> to set auto-rotation, <CODE>false</CODE>
237      * otherwise
238      */

239     public void setRotateContents(boolean rotateContents) {
240         stamper.setRotateContents(rotateContents);
241     }
242
243     /** Sets the encryption options for this document. The userPassword and the
244      * ownerPassword can be null or have zero length. In this case the ownerPassword
245      * is replaced by a random string. The open permissions for the document can be
246      * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
247      * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
248      * The permissions can be combined by ORing them.
249      * @param userPassword the user password. Can be null or empty
250      * @param ownerPassword the owner password. Can be null or empty
251      * @param permissions the user permissions
252      * @param strength128Bits <code>true</code> for 128 bit key length, <code>false</code> for 40 bit key length
253      * @throws DocumentException if anything was already written to the output
254      */

255     public void setEncryption(byte userPassword[], byte ownerPassword[], int permissions, boolean strength128Bits) throws DocumentException {
256         if (stamper.isAppend())
257             throw new DocumentException("Append mode does not support changing the encryption status.");
258         if (stamper.isContentWritten())
259             throw new DocumentException("Content was already written to the output.");
260         stamper.setEncryption(userPassword, ownerPassword, permissions, strength128Bits ? PdfWriter.STANDARD_ENCRYPTION_128 : PdfWriter.STANDARD_ENCRYPTION_40);
261     }
262
263     /** Sets the encryption options for this document. The userPassword and the
264      * ownerPassword can be null or have zero length. In this case the ownerPassword
265      * is replaced by a random string. The open permissions for the document can be
266      * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
267      * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
268      * The permissions can be combined by ORing them.
269      * @param userPassword the user password. Can be null or empty
270      * @param ownerPassword the owner password. Can be null or empty
271      * @param permissions the user permissions
272      * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128.
273      * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext
274      * @throws DocumentException if the document is already open
275      */

276     public void setEncryption(byte userPassword[], byte ownerPassword[], int permissions, int encryptionType) throws DocumentException {
277         if (stamper.isAppend())
278             throw new DocumentException("Append mode does not support changing the encryption status.");
279         if (stamper.isContentWritten())
280             throw new DocumentException("Content was already written to the output.");
281         stamper.setEncryption(userPassword, ownerPassword, permissions, encryptionType);
282     }
283
284     /**
285      * Sets the encryption options for this document. The userPassword and the
286      * ownerPassword can be null or have zero length. In this case the ownerPassword
287      * is replaced by a random string. The open permissions for the document can be
288      * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
289      * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
290      * The permissions can be combined by ORing them.
291      * @param strength <code>true</code> for 128 bit key length, <code>false</code> for 40 bit key length
292      * @param userPassword the user password. Can be null or empty
293      * @param ownerPassword the owner password. Can be null or empty
294      * @param permissions the user permissions
295      * @throws DocumentException if anything was already written to the output
296      */

297     public void setEncryption(boolean strength, String JavaDoc userPassword, String JavaDoc ownerPassword, int permissions) throws DocumentException {
298         setEncryption(DocWriter.getISOBytes(userPassword), DocWriter.getISOBytes(ownerPassword), permissions, strength);
299     }
300
301     /**
302      * Sets the encryption options for this document. The userPassword and the
303      * ownerPassword can be null or have zero length. In this case the ownerPassword
304      * is replaced by a random string. The open permissions for the document can be
305      * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
306      * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
307      * The permissions can be combined by ORing them.
308      * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128.
309      * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext
310      * @param userPassword the user password. Can be null or empty
311      * @param ownerPassword the owner password. Can be null or empty
312      * @param permissions the user permissions
313      * @throws DocumentException if anything was already written to the output
314      */

315     public void setEncryption(int encryptionType, String JavaDoc userPassword, String JavaDoc ownerPassword, int permissions) throws DocumentException {
316         setEncryption(DocWriter.getISOBytes(userPassword), DocWriter.getISOBytes(ownerPassword), permissions, encryptionType);
317     }
318
319     /**
320      * Sets the certificate encryption options for this document. An array of one or more public certificates
321      * must be provided together with an array of the same size for the permissions for each certificate.
322      * The open permissions for the document can be
323      * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
324      * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
325      * The permissions can be combined by ORing them.
326      * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext
327      * @param certs the public certificates to be used for the encryption
328      * @param permissions the user permissions for each of the certicates
329      * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128.
330      * @throws DocumentException if the encryption was set too late
331      */

332      public void setEncryption(Certificate JavaDoc[] certs, int[] permissions, int encryptionType) throws DocumentException {
333         if (stamper.isAppend())
334             throw new DocumentException("Append mode does not support changing the encryption status.");
335         if (stamper.isContentWritten())
336             throw new DocumentException("Content was already written to the output.");
337         stamper.setEncryption(certs, permissions, encryptionType);
338      }
339      
340     /** Gets a page from other PDF document. Note that calling this method more than
341      * once with the same parameters will retrieve the same object.
342      * @param reader the PDF document where the page is
343      * @param pageNumber the page number. The first page is 1
344      * @return the template representing the imported page
345      */

346     public PdfImportedPage getImportedPage(PdfReader reader, int pageNumber) {
347         return stamper.getImportedPage(reader, pageNumber);
348     }
349
350     /** Gets the underlying PdfWriter.
351      * @return the underlying PdfWriter
352      */

353     public PdfWriter getWriter() {
354         return stamper;
355     }
356
357     /** Gets the underlying PdfReader.
358      * @return the underlying PdfReader
359      */

360     public PdfReader getReader() {
361         return stamper.reader;
362     }
363
364     /** Gets the <CODE>AcroFields</CODE> object that allows to get and set field values
365      * and to merge FDF forms.
366      * @return the <CODE>AcroFields</CODE> object
367      */

368     public AcroFields getAcroFields() {
369         return stamper.getAcroFields();
370     }
371
372     /** Determines if the fields are flattened on close. The fields added with
373      * {@link #addAnnotation(PdfAnnotation,int)} will never be flattened.
374      * @param flat <CODE>true</CODE> to flatten the fields, <CODE>false</CODE>
375      * to keep the fields
376      */

377     public void setFormFlattening(boolean flat) {
378         stamper.setFormFlattening(flat);
379     }
380
381     /** Determines if the FreeText annotations are flattened on close.
382      * @param flat <CODE>true</CODE> to flatten the FreeText annotations, <CODE>false</CODE>
383      * (the default) to keep the FreeText annotations as active content.
384      */

385     public void setFreeTextFlattening(boolean flat) {
386         stamper.setFreeTextFlattening(flat);
387     }
388
389     /**
390      * Adds an annotation of form field in a specific page. This page number
391      * can be overridden with {@link PdfAnnotation#setPlaceInPage(int)}.
392      * @param annot the annotation
393      * @param page the page
394      */

395     public void addAnnotation(PdfAnnotation annot, int page) {
396         stamper.addAnnotation(annot, page);
397     }
398
399     /**
400      * Adds the comments present in an FDF file.
401      * @param fdf the FDF file
402      * @throws IOException on error
403      */

404     public void addComments(FdfReader fdf) throws IOException JavaDoc {
405         stamper.addComments(fdf);
406     }
407     
408     /**
409      * Sets the bookmarks. The list structure is defined in
410      * {@link SimpleBookmark}.
411      * @param outlines the bookmarks or <CODE>null</CODE> to remove any
412      */

413     public void setOutlines(List JavaDoc outlines) {
414         stamper.setOutlines(outlines);
415     }
416
417     /**
418      * Sets the thumbnail image for a page.
419      * @param image the image
420      * @param page the page
421      * @throws PdfException on error
422      * @throws DocumentException on error
423      */

424     public void setThumbnail(Image image, int page) throws PdfException, DocumentException {
425         stamper.setThumbnail(image, page);
426     }
427     
428     /**
429      * Adds <CODE>name</CODE> to the list of fields that will be flattened on close,
430      * all the other fields will remain. If this method is never called or is called
431      * with invalid field names, all the fields will be flattened.
432      * <p>
433      * Calling <CODE>setFormFlattening(true)</CODE> is needed to have any kind of
434      * flattening.
435      * @param name the field name
436      * @return <CODE>true</CODE> if the field exists, <CODE>false</CODE> otherwise
437      */

438     public boolean partialFormFlattening(String JavaDoc name) {
439         return stamper.partialFormFlattening(name);
440     }
441
442     /** Adds a JavaScript action at the document level. When the document
443      * opens all this JavaScript runs. The existing JavaScript will be replaced.
444      * @param js the JavaScript code
445      */

446     public void addJavaScript(String JavaDoc js) {
447         stamper.addJavaScript(js, !PdfEncodings.isPdfDocEncoding(js));
448     }
449
450     /** Adds a file attachment at the document level. Existing attachments will be kept.
451      * @param description the file description
452      * @param fileStore an array with the file. If it's <CODE>null</CODE>
453      * the file will be read from the disk
454      * @param file the path to the file. It will only be used if
455      * <CODE>fileStore</CODE> is not <CODE>null</CODE>
456      * @param fileDisplay the actual file name stored in the pdf
457      * @throws IOException on error
458      */

459     public void addFileAttachment(String JavaDoc description, byte fileStore[], String JavaDoc file, String JavaDoc fileDisplay) throws IOException JavaDoc {
460         addFileAttachment(description, PdfFileSpecification.fileEmbedded(stamper, file, fileDisplay, fileStore));
461     }
462
463     /** Adds a file attachment at the document level. Existing attachments will be kept.
464      * @param description the file description
465      * @param fs the file specification
466      */

467     public void addFileAttachment(String JavaDoc description, PdfFileSpecification fs) throws IOException JavaDoc {
468         stamper.addFileAttachment(description, fs);
469     }
470
471     /**
472      * This is the most simple way to change a PDF into a
473      * portable collection. Choose one of the following names:
474      * <ul>
475      * <li>PdfName.D (detailed view)
476      * <li>PdfName.T (tiled view)
477      * <li>PdfName.H (hidden)
478      * </ul>
479      * Pass this name as a parameter and your PDF will be
480      * a portable collection with all the embedded and
481      * attached files as entries.
482      * @param initialView can be PdfName.D, PdfName.T or PdfName.H
483      */

484     public void makePackage( PdfName initialView ) {
485         PdfCollection collection = new PdfCollection(0);
486         collection.put(PdfName.VIEW, initialView);
487         stamper.makePackage( collection );
488     }
489
490     /**
491      * Adds or replaces the Collection Dictionary in the Catalog.
492      * @param collection the new collection dictionary.
493      */

494     public void makePackage(PdfCollection collection) {
495         stamper.makePackage(collection);
496     }
497     
498     /**
499      * Sets the viewer preferences.
500      * @param preferences the viewer preferences
501      * @see PdfViewerPreferences#setViewerPreferences(int)
502      */

503     public void setViewerPreferences(int preferences) {
504         stamper.setViewerPreferences(preferences);
505     }
506     
507     /** Adds a viewer preference
508      * @param key a key for a viewer preference
509      * @param value the value for the viewer preference
510      * @see PdfViewerPreferences#addViewerPreference
511      */

512     
513     public void addViewerPreference(PdfName key, PdfObject value) {
514         stamper.addViewerPreference(key, value);
515     }
516
517     /**
518      * Sets the XMP metadata.
519      * @param xmp
520      * @see PdfWriter#setXmpMetadata(byte[])
521      */

522     public void setXmpMetadata(byte[] xmp) {
523         stamper.setXmpMetadata(xmp);
524     }
525
526     /**
527      * Gets the 1.5 compression status.
528      * @return <code>true</code> if the 1.5 compression is on
529      */

530     public boolean isFullCompression() {
531         return stamper.isFullCompression();
532     }
533
534     /**
535      * Sets the document's compression to the new 1.5 mode with object streams and xref
536      * streams. It can be set at any time but once set it can't be unset.
537      */

538     public void setFullCompression() {
539         if (stamper.isAppend())
540             return;
541         stamper.setFullCompression();
542     }
543
544     /**
545      * Sets the open and close page additional action.
546      * @param actionType the action type. It can be <CODE>PdfWriter.PAGE_OPEN</CODE>
547      * or <CODE>PdfWriter.PAGE_CLOSE</CODE>
548      * @param action the action to perform
549      * @param page the page where the action will be applied. The first page is 1
550      * @throws PdfException if the action type is invalid
551      */

552     public void setPageAction(PdfName actionType, PdfAction action, int page) throws PdfException {
553         stamper.setPageAction(actionType, action, page);
554     }
555
556     /**
557      * Sets the display duration for the page (for presentations)
558      * @param seconds the number of seconds to display the page. A negative value removes the entry
559      * @param page the page where the duration will be applied. The first page is 1
560      */

561     public void setDuration(int seconds, int page) {
562         stamper.setDuration(seconds, page);
563     }
564     
565     /**
566      * Sets the transition for the page
567      * @param transition the transition object. A <code>null</code> removes the transition
568      * @param page the page where the transition will be applied. The first page is 1
569      */

570     public void setTransition(PdfTransition transition, int page) {
571         stamper.setTransition(transition, page);
572     }
573
574     /**
575      * Applies a digital signature to a document, possibly as a new revision, making
576      * possible multiple signatures. The returned PdfStamper
577      * can be used normally as the signature is only applied when closing.
578      * <p>
579      * A possible use for adding a signature without invalidating an existing one is:
580      * <p>
581      * <pre>
582      * KeyStore ks = KeyStore.getInstance("pkcs12");
583      * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
584      * String alias = (String)ks.aliases().nextElement();
585      * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
586      * Certificate[] chain = ks.getCertificateChain(alias);
587      * PdfReader reader = new PdfReader("original.pdf");
588      * FileOutputStream fout = new FileOutputStream("signed.pdf");
589      * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', new
590      * File("/temp"), true);
591      * PdfSignatureAppearance sap = stp.getSignatureAppearance();
592      * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
593      * sap.setReason("I'm the author");
594      * sap.setLocation("Lisbon");
595      * // comment next line to have an invisible signature
596      * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
597      * stp.close();
598      * </pre>
599      * @param reader the original document
600      * @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
601      * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
602      * document
603      * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
604      * If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
605      * In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
606      * no temporary file will be created and memory will be used
607      * @param append if <CODE>true</CODE> the signature and all the other content will be added as a
608      * new revision thus not invalidating existing signatures
609      * @return a <CODE>PdfStamper</CODE>
610      * @throws DocumentException on error
611      * @throws IOException on error
612      */

613     public static PdfStamper createSignature(PdfReader reader, OutputStream JavaDoc os, char pdfVersion, File JavaDoc tempFile, boolean append) throws DocumentException, IOException JavaDoc {
614         PdfStamper stp;
615         if (tempFile == null) {
616             ByteBuffer bout = new ByteBuffer();
617             stp = new PdfStamper(reader, bout, pdfVersion, append);
618             stp.sigApp = new PdfSignatureAppearance(stp.stamper);
619             stp.sigApp.setSigout(bout);
620         }
621         else {
622             if (tempFile.isDirectory())
623                 tempFile = File.createTempFile("pdf", null, tempFile);
624             FileOutputStream JavaDoc fout = new FileOutputStream JavaDoc(tempFile);
625             stp = new PdfStamper(reader, fout, pdfVersion, append);
626             stp.sigApp = new PdfSignatureAppearance(stp.stamper);
627             stp.sigApp.setTempFile(tempFile);
628         }
629         stp.sigApp.setOriginalout(os);
630         stp.sigApp.setStamper(stp);
631         stp.hasSignature = true;
632         PdfDictionary catalog = reader.getCatalog();
633         PdfDictionary acroForm = (PdfDictionary)PdfReader.getPdfObject(catalog.get(PdfName.ACROFORM), catalog);
634         if (acroForm != null) {
635             acroForm.remove(PdfName.NEEDAPPEARANCES);
636             stp.stamper.markUsed(acroForm);
637         }
638         return stp;
639     }
640
641     /**
642      * Applies a digital signature to a document. The returned PdfStamper
643      * can be used normally as the signature is only applied when closing.
644      * <p>
645      * Note that the pdf is created in memory.
646      * <p>
647      * A possible use is:
648      * <p>
649      * <pre>
650      * KeyStore ks = KeyStore.getInstance("pkcs12");
651      * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
652      * String alias = (String)ks.aliases().nextElement();
653      * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
654      * Certificate[] chain = ks.getCertificateChain(alias);
655      * PdfReader reader = new PdfReader("original.pdf");
656      * FileOutputStream fout = new FileOutputStream("signed.pdf");
657      * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
658      * PdfSignatureAppearance sap = stp.getSignatureAppearance();
659      * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
660      * sap.setReason("I'm the author");
661      * sap.setLocation("Lisbon");
662      * // comment next line to have an invisible signature
663      * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
664      * stp.close();
665      * </pre>
666      * @param reader the original document
667      * @param os the output stream
668      * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
669      * document
670      * @throws DocumentException on error
671      * @throws IOException on error
672      * @return a <CODE>PdfStamper</CODE>
673      */

674     public static PdfStamper createSignature(PdfReader reader, OutputStream JavaDoc os, char pdfVersion) throws DocumentException, IOException JavaDoc {
675         return createSignature(reader, os, pdfVersion, null, false);
676     }
677     
678     /**
679      * Applies a digital signature to a document. The returned PdfStamper
680      * can be used normally as the signature is only applied when closing.
681      * <p>
682      * A possible use is:
683      * <p>
684      * <pre>
685      * KeyStore ks = KeyStore.getInstance("pkcs12");
686      * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
687      * String alias = (String)ks.aliases().nextElement();
688      * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
689      * Certificate[] chain = ks.getCertificateChain(alias);
690      * PdfReader reader = new PdfReader("original.pdf");
691      * FileOutputStream fout = new FileOutputStream("signed.pdf");
692      * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', new File("/temp"));
693      * PdfSignatureAppearance sap = stp.getSignatureAppearance();
694      * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
695      * sap.setReason("I'm the author");
696      * sap.setLocation("Lisbon");
697      * // comment next line to have an invisible signature
698      * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
699      * stp.close();
700      * </pre>
701      * @param reader the original document
702      * @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
703      * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
704      * document
705      * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
706      * If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
707      * In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
708      * no temporary file will be created and memory will be used
709      * @return a <CODE>PdfStamper</CODE>
710      * @throws DocumentException on error
711      * @throws IOException on error
712      */

713     public static PdfStamper createSignature(PdfReader reader, OutputStream JavaDoc os, char pdfVersion, File JavaDoc tempFile) throws DocumentException, IOException JavaDoc
714     {
715         return createSignature(reader, os, pdfVersion, tempFile, false);
716     }
717 }
Popular Tags