001/*
002 * $Id: PdfAnnotationsImp.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf.internal;
045
046import java.io.IOException;
047import java.net.URL;
048import java.util.ArrayList;
049import java.util.HashSet;
050
051import com.itextpdf.text.Annotation;
052import com.itextpdf.text.ExceptionConverter;
053import com.itextpdf.text.Rectangle;
054import com.itextpdf.text.pdf.PdfAcroForm;
055import com.itextpdf.text.pdf.PdfAction;
056import com.itextpdf.text.pdf.PdfAnnotation;
057import com.itextpdf.text.pdf.PdfArray;
058import com.itextpdf.text.pdf.PdfFileSpecification;
059import com.itextpdf.text.pdf.PdfFormField;
060import com.itextpdf.text.pdf.PdfName;
061import com.itextpdf.text.pdf.PdfObject;
062import com.itextpdf.text.pdf.PdfRectangle;
063import com.itextpdf.text.pdf.PdfString;
064import com.itextpdf.text.pdf.PdfTemplate;
065import com.itextpdf.text.pdf.PdfWriter;
066
067public class PdfAnnotationsImp {
068
069    /**
070     * This is the AcroForm object for the complete document.
071     */
072    protected PdfAcroForm acroForm;
073
074    /**
075     * This is the array containing the references to annotations
076     * that were added to the document.
077     */
078    protected ArrayList<PdfAnnotation> annotations;
079
080    /**
081     * This is an array containing references to some delayed annotations
082     * (that were added for a page that doesn't exist yet).
083     */
084    protected ArrayList<PdfAnnotation> delayedAnnotations = new ArrayList<PdfAnnotation>();
085
086
087    public PdfAnnotationsImp(PdfWriter writer) {
088        acroForm = new PdfAcroForm(writer);
089    }
090
091    /**
092     * Checks if the AcroForm is valid.
093     */
094    public boolean hasValidAcroForm() {
095        return acroForm.isValid();
096    }
097
098    /**
099     * Gets the AcroForm object.
100     * @return the PdfAcroform object of the PdfDocument
101     */
102    public PdfAcroForm getAcroForm() {
103        return acroForm;
104    }
105
106    public void setSigFlags(int f) {
107        acroForm.setSigFlags(f);
108    }
109
110    public void addCalculationOrder(PdfFormField formField) {
111        acroForm.addCalculationOrder(formField);
112    }
113
114    public void addAnnotation(PdfAnnotation annot) {
115        if (annot.isForm()) {
116            PdfFormField field = (PdfFormField)annot;
117            if (field.getParent() == null)
118                addFormFieldRaw(field);
119        }
120        else
121            annotations.add(annot);
122    }
123
124    public void addPlainAnnotation(PdfAnnotation annot) {
125        annotations.add(annot);
126    }
127
128    void addFormFieldRaw(PdfFormField field) {
129        annotations.add(field);
130        ArrayList<PdfFormField> kids = field.getKids();
131        if (kids != null) {
132            for (int k = 0; k < kids.size(); ++k)
133                addFormFieldRaw(kids.get(k));
134        }
135    }
136
137    public boolean hasUnusedAnnotations() {
138        return !annotations.isEmpty();
139    }
140
141    public void resetAnnotations() {
142        annotations = delayedAnnotations;
143        delayedAnnotations = new ArrayList<PdfAnnotation>();
144    }
145
146    public PdfArray rotateAnnotations(PdfWriter writer, Rectangle pageSize) {
147        PdfArray array = new PdfArray();
148        int rotation = pageSize.getRotation() % 360;
149        int currentPage = writer.getCurrentPageNumber();
150        for (int k = 0; k < annotations.size(); ++k) {
151            PdfAnnotation dic = annotations.get(k);
152            int page = dic.getPlaceInPage();
153            if (page > currentPage) {
154                delayedAnnotations.add(dic);
155                continue;
156            }
157            if (dic.isForm()) {
158                if (!dic.isUsed()) {
159                    HashSet<PdfTemplate> templates = dic.getTemplates();
160                    if (templates != null)
161                        acroForm.addFieldTemplates(templates);
162                }
163                PdfFormField field = (PdfFormField)dic;
164                if (field.getParent() == null)
165                    acroForm.addDocumentField(field.getIndirectReference());
166            }
167            if (dic.isAnnotation()) {
168                array.add(dic.getIndirectReference());
169                if (!dic.isUsed()) {
170                    PdfRectangle rect = (PdfRectangle)dic.get(PdfName.RECT);
171                    if (rect != null) {
172                        switch (rotation) {
173                                case 90:
174                                        dic.put(PdfName.RECT, new PdfRectangle(
175                                                        pageSize.getTop() - rect.bottom(),
176                                                                                rect.left(),
177                                                                                pageSize.getTop() - rect.top(),
178                                                                                rect.right()));
179                                        break;
180                                case 180:
181                                        dic.put(PdfName.RECT, new PdfRectangle(
182                                                        pageSize.getRight() - rect.left(),
183                                                                                pageSize.getTop() - rect.bottom(),
184                                                                                pageSize.getRight() - rect.right(),
185                                                                                pageSize.getTop() - rect.top()));
186                                        break;
187                                case 270:
188                                        dic.put(PdfName.RECT, new PdfRectangle(
189                                                        rect.bottom(),
190                                                                                pageSize.getRight() - rect.left(),
191                                                                                rect.top(),
192                                                                                pageSize.getRight() - rect.right()));
193                                        break;
194                        }
195                    }
196                }
197            }
198            if (!dic.isUsed()) {
199                dic.setUsed();
200                try {
201                    writer.addToBody(dic, dic.getIndirectReference());
202                }
203                catch (IOException e) {
204                    throw new ExceptionConverter(e);
205                }
206            }
207        }
208        return array;
209    }
210
211    public static PdfAnnotation convertAnnotation(PdfWriter writer, Annotation annot, Rectangle defaultRect) throws IOException {
212        switch(annot.annotationType()) {
213           case Annotation.URL_NET:
214               return new PdfAnnotation(writer, annot.llx(), annot.lly(), annot.urx(), annot.ury(), new PdfAction((URL) annot.attributes().get(Annotation.URL)));
215           case Annotation.URL_AS_STRING:
216               return new PdfAnnotation(writer, annot.llx(), annot.lly(), annot.urx(), annot.ury(), new PdfAction((String) annot.attributes().get(Annotation.FILE)));
217           case Annotation.FILE_DEST:
218               return new PdfAnnotation(writer, annot.llx(), annot.lly(), annot.urx(), annot.ury(), new PdfAction((String) annot.attributes().get(Annotation.FILE), (String) annot.attributes().get(Annotation.DESTINATION)));
219           case Annotation.SCREEN:
220               boolean sparams[] = (boolean[])annot.attributes().get(Annotation.PARAMETERS);
221               String fname = (String) annot.attributes().get(Annotation.FILE);
222               String mimetype = (String) annot.attributes().get(Annotation.MIMETYPE);
223               PdfFileSpecification fs;
224               if (sparams[0])
225                   fs = PdfFileSpecification.fileEmbedded(writer, fname, fname, null);
226               else
227                   fs = PdfFileSpecification.fileExtern(writer, fname);
228               PdfAnnotation ann = PdfAnnotation.createScreen(writer, new Rectangle(annot.llx(), annot.lly(), annot.urx(), annot.ury()),
229                       fname, fs, mimetype, sparams[1]);
230               return ann;
231           case Annotation.FILE_PAGE:
232               return new PdfAnnotation(writer, annot.llx(), annot.lly(), annot.urx(), annot.ury(), new PdfAction((String) annot.attributes().get(Annotation.FILE), ((Integer) annot.attributes().get(Annotation.PAGE)).intValue()));
233           case Annotation.NAMED_DEST:
234               return new PdfAnnotation(writer, annot.llx(), annot.lly(), annot.urx(), annot.ury(), new PdfAction(((Integer) annot.attributes().get(Annotation.NAMED)).intValue()));
235           case Annotation.LAUNCH:
236               return new PdfAnnotation(writer, annot.llx(), annot.lly(), annot.urx(), annot.ury(), new PdfAction((String) annot.attributes().get(Annotation.APPLICATION),(String) annot.attributes().get(Annotation.PARAMETERS),(String) annot.attributes().get(Annotation.OPERATION),(String) annot.attributes().get(Annotation.DEFAULTDIR)));
237           default:
238                   return new PdfAnnotation(writer, defaultRect.getLeft(), defaultRect.getBottom(), defaultRect.getRight(), defaultRect.getTop(), new PdfString(annot.title(), PdfObject.TEXT_UNICODE), new PdfString(annot.content(), PdfObject.TEXT_UNICODE));
239       }
240   }
241}