001: /**
002: * Copyright (c) 2003-2005, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.interactive.annotation;
031:
032: import java.io.IOException;
033:
034: import org.pdfbox.cos.COSArray;
035: import org.pdfbox.cos.COSDictionary;
036: import org.pdfbox.cos.COSName;
037:
038: import org.pdfbox.pdmodel.common.COSObjectable;
039: import org.pdfbox.pdmodel.common.PDRectangle;
040: import org.pdfbox.pdmodel.graphics.color.PDGamma;
041: import org.pdfbox.pdmodel.interactive.action.PDActionFactory;
042: import org.pdfbox.pdmodel.interactive.action.PDAdditionalActions;
043: import org.pdfbox.pdmodel.interactive.action.type.PDAction;
044: import org.pdfbox.util.BitFlagHelper;
045: import org.pdfbox.cos.COSBase;
046:
047: /**
048: * This class represents a PDF annotation.
049: *
050: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
051: * @version $Revision: 1.14 $
052: */
053: public abstract class PDAnnotation implements COSObjectable {
054: /**
055: * An annotation flag.
056: */
057: public static final int FLAG_INVISIBLE = 1 << 0;
058: /**
059: * An annotation flag.
060: */
061: public static final int FLAG_HIDDEN = 1 << 1;
062: /**
063: * An annotation flag.
064: */
065: public static final int FLAG_PRINTED = 1 << 2;
066: /**
067: * An annotation flag.
068: */
069: public static final int FLAG_NO_ZOOM = 1 << 3;
070: /**
071: * An annotation flag.
072: */
073: public static final int FLAG_NO_ROTATE = 1 << 4;
074: /**
075: * An annotation flag.
076: */
077: public static final int FLAG_NO_VIEW = 1 << 5;
078: /**
079: * An annotation flag.
080: */
081: public static final int FLAG_READ_ONLY = 1 << 6;
082: /**
083: * An annotation flag.
084: */
085: public static final int FLAG_LOCKED = 1 << 7;
086: /**
087: * An annotation flag.
088: */
089: public static final int FLAG_TOGGLE_NO_VIEW = 1 << 8;
090:
091: private COSDictionary dictionary;
092:
093: /**
094: * Create the correct annotation from the base COS object.
095: *
096: * @param base The COS object that is the annotation.
097: * @return The correctly typed annotation object.
098: * @throws IOException If there is an error while creating the annotation.
099: */
100: public static PDAnnotation createAnnotation(COSBase base)
101: throws IOException {
102: PDAnnotation annot = null;
103: if (base instanceof COSDictionary) {
104: COSDictionary annotDic = (COSDictionary) base;
105: String subtype = annotDic.getNameAsString(COSName.SUBTYPE);
106: if (subtype.equals(PDAnnotationRubberStamp.SUB_TYPE)) {
107: annot = new PDAnnotationRubberStamp(annotDic);
108: } else if (subtype.equals(PDAnnotationLink.SUB_TYPE)) {
109: annot = new PDAnnotationLink(annotDic);
110: } else if (subtype.equals(PDAnnotationText.SUB_TYPE)) {
111: annot = new PDAnnotationText(annotDic);
112: } else if (subtype.equals(PDAnnotationLine.SUB_TYPE)) {
113: annot = new PDAnnotationLine(annotDic);
114: } else if (subtype
115: .equals(PDAnnotationSquareCircle.SUB_TYPE_SQUARE)
116: || subtype
117: .equals(PDAnnotationSquareCircle.SUB_TYPE_CIRCLE)) {
118: annot = new PDAnnotationSquareCircle(annotDic);
119: } else if (subtype.equals(PDAnnotationLink.SUB_TYPE)) {
120: annot = new PDAnnotationLink(annotDic);
121: } else if (subtype
122: .equals(PDAnnotationFileAttachment.SUB_TYPE)) {
123: annot = new PDAnnotationFileAttachment(annotDic);
124: } else if (subtype
125: .equals(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT)
126: || subtype
127: .equals(PDAnnotationTextMarkup.SUB_TYPE_UNDERLINE)
128: || subtype
129: .equals(PDAnnotationTextMarkup.SUB_TYPE_SQUIGGLY)
130: || subtype
131: .equals(PDAnnotationTextMarkup.SUB_TYPE_STRIKEOUT)) {
132: annot = new PDAnnotationTextMarkup(annotDic);
133: } else {
134: annot = new PDAnnotationUnknown(annotDic);
135: }
136: } else {
137: throw new IOException("Error: Unknown annotation type "
138: + base);
139: }
140:
141: return annot;
142: }
143:
144: /**
145: * Constructor.
146: */
147: public PDAnnotation() {
148: dictionary = new COSDictionary();
149: dictionary.setItem(COSName.TYPE, COSName.getPDFName("Annot"));
150: }
151:
152: /**
153: * Constructor.
154: *
155: * @param dict The annotations dictionary.
156: */
157: public PDAnnotation(COSDictionary dict) {
158: dictionary = dict;
159: }
160:
161: /**
162: * returns the dictionary.
163: * @return the dictionary
164: */
165: public COSDictionary getDictionary() {
166: return dictionary;
167: }
168:
169: /**
170: * The annotation rectangle, defining the location of the annotation
171: * on the page in default user space units. This is usually required and should
172: * not return null on valid PDF documents. But where this is a parent form field
173: * with children, such as radio button collections then the rectangle will be null.
174: *
175: * @return The Rect value of this annotation.
176: */
177: public PDRectangle getRectangle() {
178: COSArray rectArray = (COSArray) dictionary
179: .getDictionaryObject(COSName.getPDFName("Rect"));
180: PDRectangle rectangle = null;
181: if (rectArray != null) {
182: rectangle = new PDRectangle(rectArray);
183: }
184: return rectangle;
185: }
186:
187: /**
188: * This will set the rectangle for this annotation.
189: *
190: * @param rectangle The new rectangle values.
191: */
192: public void setRectangle(PDRectangle rectangle) {
193: dictionary.setItem(COSName.getPDFName("Rect"), rectangle
194: .getCOSArray());
195: }
196:
197: /**
198: * This will get the flags for this field.
199: *
200: * @return flags The set of flags.
201: */
202: public int getAnnotationFlags() {
203: return getDictionary().getInt("F", 0);
204: }
205:
206: /**
207: * This will set the flags for this field.
208: *
209: * @param flags The new flags.
210: */
211: public void setAnnotationFlags(int flags) {
212: getDictionary().setInt("F", flags);
213: }
214:
215: /**
216: * Interface method for COSObjectable.
217: *
218: * @return This object as a standard COS object.
219: */
220: public COSBase getCOSObject() {
221: return getDictionary();
222: }
223:
224: /**
225: * This will get the name of the current appearance stream if any.
226: *
227: * @return The name of the appearance stream.
228: */
229: public String getAppearanceStream() {
230: String retval = null;
231: COSName name = (COSName) getDictionary().getDictionaryObject(
232: COSName.getPDFName("AS"));
233: if (name != null) {
234: retval = name.getName();
235: }
236: return retval;
237: }
238:
239: /**
240: * This will set the annotations appearance stream name.
241: *
242: * @param as The name of the appearance stream.
243: */
244: public void setAppearanceStream(String as) {
245: if (as == null) {
246: getDictionary().removeItem(COSName.getPDFName("AS"));
247: } else {
248: getDictionary().setItem(COSName.getPDFName("AS"),
249: COSName.getPDFName(as));
250: }
251: }
252:
253: /**
254: * This will get the appearance dictionary associated with this annotation.
255: * This may return null.
256: *
257: * @return This annotations appearance.
258: */
259: public PDAppearanceDictionary getAppearance() {
260: PDAppearanceDictionary ap = null;
261: COSDictionary apDic = (COSDictionary) dictionary
262: .getDictionaryObject(COSName.getPDFName("AP"));
263: if (apDic != null) {
264: ap = new PDAppearanceDictionary(apDic);
265: }
266: return ap;
267: }
268:
269: /**
270: * This will set the appearance associated with this annotation.
271: *
272: * @param appearance The appearance dictionary for this annotation.
273: */
274: public void setAppearance(PDAppearanceDictionary appearance) {
275: COSDictionary ap = null;
276: if (appearance != null) {
277: ap = appearance.getDictionary();
278: }
279: dictionary.setItem(COSName.getPDFName("AP"), ap);
280: }
281:
282: /**
283: * Get the invisible flag.
284: *
285: * @return The invisible flag.
286: */
287: public boolean isInvisible() {
288: return BitFlagHelper.getFlag(getDictionary(), "F",
289: FLAG_INVISIBLE);
290: }
291:
292: /**
293: * Set the invisible flag.
294: *
295: * @param invisible The new invisible flag.
296: */
297: public void setInvisible(boolean invisible) {
298: BitFlagHelper.setFlag(getDictionary(), "F", FLAG_INVISIBLE,
299: invisible);
300: }
301:
302: /**
303: * Get the hidden flag.
304: *
305: * @return The hidden flag.
306: */
307: public boolean isHidden() {
308: return BitFlagHelper.getFlag(getDictionary(), "F", FLAG_HIDDEN);
309: }
310:
311: /**
312: * Set the hidden flag.
313: *
314: * @param hidden The new hidden flag.
315: */
316: public void setHidden(boolean hidden) {
317: BitFlagHelper
318: .setFlag(getDictionary(), "F", FLAG_HIDDEN, hidden);
319: }
320:
321: /**
322: * Get the printed flag.
323: *
324: * @return The printed flag.
325: */
326: public boolean isPrinted() {
327: return BitFlagHelper
328: .getFlag(getDictionary(), "F", FLAG_PRINTED);
329: }
330:
331: /**
332: * Set the printed flag.
333: *
334: * @param printed The new printed flag.
335: */
336: public void setPrinted(boolean printed) {
337: BitFlagHelper.setFlag(getDictionary(), "F", FLAG_PRINTED,
338: printed);
339: }
340:
341: /**
342: * Get the noZoom flag.
343: *
344: * @return The noZoom flag.
345: */
346: public boolean isNoZoom() {
347: return BitFlagHelper
348: .getFlag(getDictionary(), "F", FLAG_NO_ZOOM);
349: }
350:
351: /**
352: * Set the noZoom flag.
353: *
354: * @param noZoom The new noZoom flag.
355: */
356: public void setNoZoom(boolean noZoom) {
357: BitFlagHelper.setFlag(getDictionary(), "F", FLAG_NO_ZOOM,
358: noZoom);
359: }
360:
361: /**
362: * Get the noRotate flag.
363: *
364: * @return The noRotate flag.
365: */
366: public boolean isNoRotate() {
367: return BitFlagHelper.getFlag(getDictionary(), "F",
368: FLAG_NO_ROTATE);
369: }
370:
371: /**
372: * Set the noRotate flag.
373: *
374: * @param noRotate The new noRotate flag.
375: */
376: public void setNoRotate(boolean noRotate) {
377: BitFlagHelper.setFlag(getDictionary(), "F", FLAG_NO_ROTATE,
378: noRotate);
379: }
380:
381: /**
382: * Get the noView flag.
383: *
384: * @return The noView flag.
385: */
386: public boolean isNoView() {
387: return BitFlagHelper
388: .getFlag(getDictionary(), "F", FLAG_NO_VIEW);
389: }
390:
391: /**
392: * Set the noView flag.
393: *
394: * @param noView The new noView flag.
395: */
396: public void setNoView(boolean noView) {
397: BitFlagHelper.setFlag(getDictionary(), "F", FLAG_NO_VIEW,
398: noView);
399: }
400:
401: /**
402: * Get the readOnly flag.
403: *
404: * @return The readOnly flag.
405: */
406: public boolean isReadOnly() {
407: return BitFlagHelper.getFlag(getDictionary(), "F",
408: FLAG_READ_ONLY);
409: }
410:
411: /**
412: * Set the readOnly flag.
413: *
414: * @param readOnly The new readOnly flag.
415: */
416: public void setReadOnly(boolean readOnly) {
417: BitFlagHelper.setFlag(getDictionary(), "F", FLAG_READ_ONLY,
418: readOnly);
419: }
420:
421: /**
422: * Get the locked flag.
423: *
424: * @return The locked flag.
425: */
426: public boolean isLocked() {
427: return BitFlagHelper.getFlag(getDictionary(), "F", FLAG_LOCKED);
428: }
429:
430: /**
431: * Set the locked flag.
432: *
433: * @param locked The new locked flag.
434: */
435: public void setLocked(boolean locked) {
436: BitFlagHelper
437: .setFlag(getDictionary(), "F", FLAG_LOCKED, locked);
438: }
439:
440: /**
441: * Get the toggleNoView flag.
442: *
443: * @return The toggleNoView flag.
444: */
445: public boolean isToggleNoView() {
446: return BitFlagHelper.getFlag(getDictionary(), "F",
447: FLAG_TOGGLE_NO_VIEW);
448: }
449:
450: /**
451: * Set the toggleNoView flag.
452: *
453: * @param toggleNoView The new toggleNoView flag.
454: */
455: public void setToggleNoView(boolean toggleNoView) {
456: BitFlagHelper.setFlag(getDictionary(), "F",
457: FLAG_TOGGLE_NO_VIEW, toggleNoView);
458: }
459:
460: /**
461: * Get the action to be performed when this annotation is to be activated.
462: *
463: * @return The action to be performed when this annotation is activated.
464: *
465: * @throws IOException If there is an error creating the action.
466: */
467: public PDAction getAction() throws IOException {
468: COSDictionary action = (COSDictionary) getDictionary()
469: .getDictionaryObject(COSName.A);
470: return PDActionFactory.createAction(action);
471: }
472:
473: /**
474: * Set the annotation action.
475: * As of PDF 1.6 this is only used for Widget Annotations
476: * @param action The annotation action.
477: */
478: public void setAction(PDAction action) {
479: getDictionary().setItem(COSName.A, action);
480: }
481:
482: /**
483: * Get the additional actions for this field. This will return null
484: * if there are no additional actions for this field.
485: * As of PDF 1.6 this is only used for Widget Annotations.
486: *
487: * @return The actions of the field.
488: */
489: public PDAdditionalActions getActions() {
490: COSDictionary aa = (COSDictionary) dictionary
491: .getDictionaryObject("AA");
492: PDAdditionalActions retval = null;
493: if (aa != null) {
494: retval = new PDAdditionalActions(aa);
495: }
496: return retval;
497: }
498:
499: /**
500: * Set the actions of the field.
501: *
502: * @param actions The field actions.
503: */
504: public void setActions(PDAdditionalActions actions) {
505: dictionary.setItem("AA", actions);
506: }
507:
508: /**
509: * Get the "contents" of the field.
510: *
511: * @return the value of the contents.
512: */
513: public String getContents() {
514: return dictionary.getString(COSName.CONTENTS);
515: }
516:
517: /**
518: * Set the "contents" of the field.
519: *
520: * @param value the value of the contents.
521: */
522: public void setContents(String value) {
523: dictionary.setString(COSName.CONTENTS, value);
524: }
525:
526: /**
527: * This will set the border style dictionary, specifying the width and dash
528: * pattern used in drawing the line.
529: *
530: * @param bs the border style dictionary to set.
531: *
532: */
533: public void setBorderStyle(PDBorderStyleDictionary bs) {
534: getDictionary().setItem("BS", bs);
535: }
536:
537: /**
538: * This will retrieve the border style dictionary, specifying the width and
539: * dash pattern used in drawing the line.
540: *
541: * @return the border style dictionary.
542: */
543: public PDBorderStyleDictionary getBoderStyle() {
544: COSDictionary bs = (COSDictionary) getDictionary().getItem(
545: COSName.getPDFName("BS"));
546: if (bs != null) {
547: return new PDBorderStyleDictionary(bs);
548: } else {
549: return null;
550: }
551: }
552:
553: /**
554: * This will retrieve the date and time the annotation was modified.
555: *
556: * @return the modified date/time (often in date format, but can be an arbitary string).
557: */
558: public String getModifiedDate() {
559: return getDictionary().getString("M");
560: }
561:
562: /**
563: * This will set the the date and time the annotation was modified.
564: *
565: * @param m
566: * the date and time the annotation was created.
567: */
568: public void setModifiedDate(String m) {
569: getDictionary().setString("M", m);
570: }
571:
572: /**
573: * This will get the name, a string intended to uniquely identify each annotatoin
574: * within a page. Not to be confused with some annotations Name entry which
575: * impact the default image drawn for them.
576: *
577: * @return The identifying name for the Annotion.
578: */
579: public String getAnnotationName() {
580: return getDictionary().getString("NM");
581: }
582:
583: /**
584: * This will set the name, a string intended to uniquely identify each annotatoin
585: * within a page. Not to be confused with some annotations Name entry which
586: * impact the default image drawn for them.
587: *
588: * @param nm The identifying name for the annotation.
589: */
590: public void setAnnotationName(String nm) {
591: getDictionary().setString("NM", nm);
592: }
593:
594: /**
595: * This will set the colour used in drawing various elements.
596: * As of PDF 1.6 these are : Background of icon when closed
597: * Title bar of popup window
598: * Border of a link annotation
599: *
600: * Colour is in DeviceRGB colourspace
601: *
602: * @param c
603: * colour in the DeviceRGB colourspace
604: *
605: */
606: public void setColour(PDGamma c) {
607: getDictionary().setItem("C", c);
608: }
609:
610: /**
611: * This will retrieve the colour used in drawing various elements.
612: * As of PDF 1.6 these are : Background of icon when closed
613: * Title bar of popup window
614: * Border of a link annotation
615: *
616: * Colour is in DeviceRGB colourspace
617: *
618: * @return PDGamma object representing the colour
619: *
620: */
621: public PDGamma getColour() {
622: COSArray c = (COSArray) getDictionary().getItem(
623: COSName.getPDFName("C"));
624: if (c != null) {
625: return new PDGamma(c);
626: } else {
627: return null;
628: }
629: }
630: }
|