com.itextpdf.kernel.pdf.annot.PdfAnnotation Maven / Gradle / Ivy
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2023 Apryse Group NV
Authors: Apryse Software.
This program is offered under a commercial and under the AGPL license.
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
AGPL licensing:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package com.itextpdf.kernel.pdf.annot;
import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.DeviceCmyk;
import com.itextpdf.kernel.colors.DeviceGray;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfAnnotationBorder;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfIndirectReference;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfObject;
import com.itextpdf.kernel.pdf.PdfObjectWrapper;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.filespec.PdfFileSpec;
import com.itextpdf.kernel.pdf.layer.IPdfOCG;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a super class for the annotation dictionary wrappers. Derived classes represent
* different standard types of annotations. See ISO-320001 12.5.6, "Annotation Types."
*/
public abstract class PdfAnnotation extends PdfObjectWrapper {
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int INVISIBLE = 1;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int HIDDEN = 2;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int PRINT = 4;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int NO_ZOOM = 8;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int NO_ROTATE = 16;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int NO_VIEW = 32;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int READ_ONLY = 64;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int LOCKED = 128;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int TOGGLE_NO_VIEW = 256;
/**
* Annotation flag.
* See also {@link PdfAnnotation#setFlag(int)} and ISO-320001, table 165.
*/
public static final int LOCKED_CONTENTS = 512;
/**
* Widget annotation highlighting mode. See ISO-320001, Table 188 (H key).
* Also see {@link PdfWidgetAnnotation#setHighlightMode(PdfName)}.
*/
public static final PdfName HIGHLIGHT_NONE = PdfName.N;
/**
* Widget annotation highlighting mode. See ISO-320001, Table 188 (H key).
* Also see {@link PdfWidgetAnnotation#setHighlightMode(PdfName)}.
*/
public static final PdfName HIGHLIGHT_INVERT = PdfName.I;
/**
* Widget annotation highlighting mode. See ISO-320001, Table 188 (H key).
* Also see {@link PdfWidgetAnnotation#setHighlightMode(PdfName)}.
*/
public static final PdfName HIGHLIGHT_OUTLINE = PdfName.O;
/**
* Widget annotation highlighting mode. See ISO-320001, Table 188 (H key).
* Also see {@link PdfWidgetAnnotation#setHighlightMode(PdfName)}.
*/
public static final PdfName HIGHLIGHT_PUSH = PdfName.P;
/**
* Widget annotation highlighting mode. See ISO-320001, Table 188 (H key).
* Also see {@link PdfWidgetAnnotation#setHighlightMode(PdfName)}.
*/
public static final PdfName HIGHLIGHT_TOGGLE = PdfName.T;
/**
* Annotation border style. See ISO-320001, Table 166 (S key).
*/
public static final PdfName STYLE_SOLID = PdfName.S;
/**
* Annotation border style. See ISO-320001, Table 166 (S key).
*/
public static final PdfName STYLE_DASHED = PdfName.D;
/**
* Annotation border style. See ISO-320001, Table 166 (S key).
*/
public static final PdfName STYLE_BEVELED = PdfName.B;
/**
* Annotation border style. See ISO-320001, Table 166 (S key).
*/
public static final PdfName STYLE_INSET = PdfName.I;
/**
* Annotation border style. See ISO-320001, Table 166 (S key).
*/
public static final PdfName STYLE_UNDERLINE = PdfName.U;
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString Marked = new PdfString("Marked");
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString Unmarked = new PdfString("Unmarked");
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString Accepted = new PdfString("Accepted");
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString Rejected = new PdfString("Rejected");
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString Canceled = new PdfString("Cancelled");
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString Completed = new PdfString("Completed");
/**
* Annotation state. See ISO-320001 12.5.6.3 "Annotation States" and Table 171 in particular.
* Also see {@link PdfTextAnnotation#setState(PdfString)}.
*/
public static final PdfString None = new PdfString("None");
/**
* Annotation state model. See ISO-320001, Table 172 (StateModel key).
* Also see {@link PdfTextAnnotation#setStateModel(PdfString)}.
*/
public static final PdfString MarkedModel = new PdfString("Marked");
/**
* Annotation state model. See ISO-320001, Table 172 (StateModel key).
* Also see {@link PdfTextAnnotation#setStateModel(PdfString)}.
*/
public static final PdfString ReviewModel = new PdfString("Review");
protected PdfPage page;
/**
* Factory method that creates the type specific {@link PdfAnnotation} from the given {@link PdfObject}
* that represents annotation object. This method is useful for property reading in reading mode or
* modifying in stamping mode. See derived classes of this class to see possible specific annotation types
* created.
*
* @param pdfObject a {@link PdfObject} that represents annotation in the document.
* @return created {@link PdfAnnotation}.
*/
public static PdfAnnotation makeAnnotation(PdfObject pdfObject) {
PdfAnnotation annotation = null;
if (pdfObject.isIndirectReference())
pdfObject = ((PdfIndirectReference) pdfObject).getRefersTo();
if (pdfObject.isDictionary()) {
PdfDictionary dictionary = (PdfDictionary) pdfObject;
PdfName subtype = dictionary.getAsName(PdfName.Subtype);
if (PdfName.Link.equals(subtype)) {
annotation = new PdfLinkAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Popup.equals(subtype)) {
annotation = new PdfPopupAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Widget.equals(subtype)) {
annotation = new PdfWidgetAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Screen.equals(subtype)) {
annotation = new PdfScreenAnnotation((PdfDictionary) pdfObject);
} else if (PdfName._3D.equals(subtype)) {
annotation = new Pdf3DAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Highlight.equals(subtype) || PdfName.Underline.equals(subtype) || PdfName.Squiggly.equals(subtype) || PdfName.StrikeOut.equals(subtype)) {
annotation = new PdfTextMarkupAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Caret.equals(subtype)) {
annotation = new PdfCaretAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Text.equals(subtype)) {
annotation = new PdfTextAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Sound.equals(subtype)) {
annotation = new PdfSoundAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Stamp.equals(subtype)) {
annotation = new PdfStampAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.FileAttachment.equals(subtype)) {
annotation = new PdfFileAttachmentAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Ink.equals(subtype)) {
annotation = new PdfInkAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.PrinterMark.equals(subtype)) {
annotation = new PdfPrinterMarkAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.TrapNet.equals(subtype)) {
annotation = new PdfTrapNetworkAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.FreeText.equals(subtype)) {
annotation = new PdfFreeTextAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Square.equals(subtype)) {
annotation = new PdfSquareAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Circle.equals(subtype)) {
annotation = new PdfCircleAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Line.equals(subtype)) {
annotation = new PdfLineAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Polygon.equals(subtype)) {
annotation = new PdfPolygonAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.PolyLine.equals(subtype)) {
annotation = new PdfPolylineAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Redact.equals(subtype)) {
annotation = new PdfRedactAnnotation((PdfDictionary) pdfObject);
} else if (PdfName.Watermark.equals(subtype)) {
annotation = new PdfWatermarkAnnotation((PdfDictionary) pdfObject);
} else {
annotation = new PdfUnknownAnnotation((PdfDictionary) pdfObject);
}
}
return annotation;
}
protected PdfAnnotation(Rectangle rect) {
this(new PdfDictionary());
put(PdfName.Rect, new PdfArray(rect));
put(PdfName.Subtype, getSubtype());
}
protected PdfAnnotation(PdfDictionary pdfObject) {
super(pdfObject);
markObjectAsIndirect(getPdfObject());
}
/**
* Gets a {@link PdfName} which value is a subtype of this annotation.
* See ISO-320001 12.5.6, "Annotation Types" for the reference to the possible types.
*
* @return subtype of this annotation.
*/
public abstract PdfName getSubtype();
/**
* Sets the layer this annotation belongs to.
*
* @param layer the layer this annotation belongs to
*/
public void setLayer(IPdfOCG layer) {
getPdfObject().put(PdfName.OC, layer.getIndirectReference());
}
/**
* Gets the text that shall be displayed for the annotation or, if this type of annotation does not display text,
* an alternate description of the annotation’s contents in human-readable form.
*
* @return annotation text content.
*/
public PdfString getContents() {
return getPdfObject().getAsString(PdfName.Contents);
}
/**
* Sets the text that shall be displayed for the annotation or, if this type of annotation does not display text,
* an alternate description of the annotation’s contents in human-readable form.
*
* @param contents a {@link PdfString} containing text content to be set to the annotation.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setContents(PdfString contents) {
return put(PdfName.Contents, contents);
}
/**
* Sets the text that shall be displayed for the annotation or, if this type of annotation does not display text,
* an alternate description of the annotation’s contents in human-readable form.
*
* @param contents a java {@link String} containing text content to be set to the annotation.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setContents(String contents) {
return setContents(new PdfString(contents, PdfEncodings.UNICODE_BIG));
}
/**
* Gets a {@link PdfDictionary} that represents a page of the document on which annotation is placed,
* i.e. which has this annotation in it's /Annots array.
*
* @return {@link PdfDictionary} that is a page pdf object or null if annotation is not added to the page yet.
*/
public PdfDictionary getPageObject() {
return getPdfObject().getAsDictionary(PdfName.P);
}
/**
* Gets a {@link PdfPage} on which annotation is placed.
*
* @return {@link PdfPage} on which annotation is placed or null if annotation is not placed yet.
*/
public PdfPage getPage() {
PdfIndirectReference annotationIndirectReference;
if (page == null && (annotationIndirectReference = getPdfObject().getIndirectReference()) != null) {
PdfDocument doc = annotationIndirectReference.getDocument();
PdfDictionary pageDictionary = getPageObject();
if (pageDictionary != null) {
page = doc.getPage(pageDictionary);
} else {
for (int i = 1; i <= doc.getNumberOfPages(); i++) {
PdfPage docPage = doc.getPage(i);
if (!docPage.isFlushed()) {
for (PdfAnnotation annot : docPage.getAnnotations()) {
if (annotationIndirectReference.equals(annot.getPdfObject().getIndirectReference())) {
page = docPage;
break;
}
}
}
}
}
}
return page;
}
/**
* Method that modifies annotation page property, which defines to which page annotation belongs.
* Keep in mind that this doesn't actually add an annotation to the page,
* it should be done via {@link PdfPage#addAnnotation(PdfAnnotation)}.
* Also you don't need to set this property manually, this is done automatically on addition to the page.
*
* @param page the {@link PdfPage} to which annotation will be added.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setPage(PdfPage page) {
this.page = page;
// Explicitly using object indirect reference here in order to correctly process released objects.
return put(PdfName.P, page.getPdfObject().getIndirectReference());
}
/**
* Gets the annotation name, a text string uniquely identifying it among all the
* annotations on its page.
*
* @return a {@link PdfString} with annotation name as it's value or null if name
* is not specified.
*/
public PdfString getName() {
return getPdfObject().getAsString(PdfName.NM);
}
/**
* Sets the annotation name, a text string uniquely identifying it among all the
* annotations on its page.
*
* @param name a {@link PdfString} to be set as annotation name.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setName(PdfString name) {
return put(PdfName.NM, name);
}
/**
* The date and time when the annotation was most recently modified.
* This is an optional property of the annotation.
*
* @return a {@link PdfString} with the modification date as it's value or null if date is not specified.
*/
public PdfString getDate() {
return getPdfObject().getAsString(PdfName.M);
}
/**
* The date and time when the annotation was most recently modified.
*
* @param date a {@link PdfString} with date. The format should be a date string as described
* in ISO-320001 7.9.4, "Dates".
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setDate(PdfString date) {
return put(PdfName.M, date);
}
/**
* A set of flags specifying various characteristics of the annotation (see ISO-320001 12.5.3, "Annotation Flags").
* For specific annotation flag constants see {@link PdfAnnotation#setFlag(int)}.
* Default value: 0.
*
* @return an integer interpreted as one-bit flags specifying various characteristics of the annotation.
*/
public int getFlags() {
PdfNumber f = getPdfObject().getAsNumber(PdfName.F);
if (f != null)
return f.intValue();
else
return 0;
}
/**
* Sets a set of flags specifying various characteristics of the annotation (see ISO-320001 12.5.3, "Annotation Flags").
* On the contrary from {@link PdfAnnotation#setFlag(int)}, this method sets a complete set of enabled and disabled flags at once.
* If not set specifically the default value is 0.
*
* @param flags an integer interpreted as set of one-bit flags specifying various characteristics of the annotation.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setFlags(int flags) {
return put(PdfName.F, new PdfNumber(flags));
}
/**
* Sets a flag that specifies a characteristic of the annotation to enabled state (see ISO-320001 12.5.3, "Annotation Flags").
* On the contrary from {@link PdfAnnotation#setFlags(int)}, this method sets only specified flags to enabled state,
* but doesn't disable other flags.
* Possible flags:
*
* - {@link PdfAnnotation#INVISIBLE} - If set, do not display the annotation if it does not belong to one of the
* standard annotation types and no annotation handler is available. If clear, display such unknown annotation
* using an appearance stream specified by its appearance dictionary, if any.
*
*
- {@link PdfAnnotation#HIDDEN} - If set, do not display or print the annotation or allow it to interact with
* the user, regardless of its annotation type or whether an annotation handler is available.
*
*
- {@link PdfAnnotation#PRINT} - If set, print the annotation when the page is printed. If clear, never print
* the annotation, regardless of whether it is displayed on the screen.
*
*
- {@link PdfAnnotation#NO_ZOOM} - If set, do not scale the annotation’s appearance to match the magnification of
* the page. The location of the annotation on the page (defined by the upper-left corner of its annotation
* rectangle) shall remain fixed, regardless of the page magnification.}
*
*
- {@link PdfAnnotation#NO_ROTATE} - If set, do not rotate the annotation’s appearance to match the rotation
* of the page. The upper-left corner of the annotation rectangle shall remain in a fixed location on the page,
* regardless of the page rotation.
*
*
- {@link PdfAnnotation#NO_VIEW} - If set, do not display the annotation on the screen or allow it to interact
* with the user. The annotation may be printed (depending on the setting of the Print flag) but should be considered
* hidden for purposes of on-screen display and user interaction.
*
*
- {@link PdfAnnotation#READ_ONLY} - If set, do not allow the annotation to interact with the user. The annotation
* may be displayed or printed (depending on the settings of the NoView and Print flags) but should not respond to mouse
* clicks or change its appearance in response to mouse motions.
*
*
- {@link PdfAnnotation#LOCKED} - If set, do not allow the annotation to be deleted or its properties
* (including position and size) to be modified by the user. However, this flag does not restrict changes to
* the annotation’s contents, such as the value of a form field.
*
*
- {@link PdfAnnotation#TOGGLE_NO_VIEW} - If set, invert the interpretation of the NoView flag for certain events.
*
*
- {@link PdfAnnotation#LOCKED_CONTENTS} - If set, do not allow the contents of the annotation to be modified
* by the user. This flag does not restrict deletion of the annotation or changes to other annotation properties,
* such as position and size.
*
*
*
* @param flag - an integer interpreted as set of one-bit flags which will be enabled for this annotation.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setFlag(int flag) {
int flags = getFlags();
flags = flags | flag;
return setFlags(flags);
}
/**
* Resets a flag that specifies a characteristic of the annotation to disabled state (see ISO-320001 12.5.3, "Annotation Flags").
*
* @param flag an integer interpreted as set of one-bit flags which will be reset to disabled state.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation resetFlag(int flag) {
int flags = getFlags();
flags = flags & ~flag;
return setFlags(flags);
}
/**
* Checks if the certain flag that specifies a characteristic of the annotation
* is in enabled state (see ISO-320001 12.5.3, "Annotation Flags").
* This method allows only one flag to be checked at once, use constants listed in {@link PdfAnnotation#setFlag(int)}.
*
* @param flag an integer interpreted as set of one-bit flags. Only one bit must be set in this integer, otherwise
* exception is thrown.
* @return true if the given flag is in enabled state.
*/
public boolean hasFlag(int flag) {
if (flag == 0) {
return false;
}
if ((flag & flag - 1) != 0) {
throw new IllegalArgumentException("Only one flag must be checked at once.");
}
int flags = getFlags();
return (flags & flag) != 0;
}
/**
* An appearance dictionary specifying how the annotation shall be presented visually on the page during its
* interactions with the user (see ISO-320001 12.5.5, "Appearance Streams"). An appearance dictionary is a dictionary
* containing one or several appearance streams or subdictionaries.
*
* @return an appearance {@link PdfDictionary} or null if it is not specified.
*/
public PdfDictionary getAppearanceDictionary() {
return getPdfObject().getAsDictionary(PdfName.AP);
}
/**
* Specific appearance object corresponding to the specific appearance type. This object might be either an appearance
* stream or an appearance subdictionary. In the latter case, the subdictionary defines multiple appearance streams
* corresponding to different appearance states of the annotation. See ISO-320001 12.5.5, "Appearance Streams".
*
* @param appearanceType a {@link PdfName} specifying appearance type. Possible types are {@link PdfName#N Normal},
* {@link PdfName#R Rollover} and {@link PdfName#D Down}.
* @return null if their is no such appearance type or an appearance object which might be either
* an appearance stream or an appearance subdictionary.
*/
public PdfDictionary getAppearanceObject(PdfName appearanceType) {
PdfDictionary ap = getAppearanceDictionary();
if (ap != null) {
PdfObject apObject = ap.get(appearanceType);
if (apObject instanceof PdfDictionary) {
return (PdfDictionary) apObject;
}
}
return null;
}
/**
* The normal appearance is used when the annotation is not interacting with the user.
* This appearance is also used for printing the annotation.
* See also {@link PdfAnnotation#getAppearanceObject(PdfName)}.
*
* @return an appearance object which might be either an appearance stream or an appearance subdictionary.
*/
public PdfDictionary getNormalAppearanceObject() {
return getAppearanceObject(PdfName.N);
}
/**
* The rollover appearance is used when the user moves the cursor into the annotation’s active area
* without pressing the mouse button. If not specified normal appearance is used.
* See also {@link PdfAnnotation#getAppearanceObject(PdfName)}.
*
* @return null if rollover appearance is not specified or an appearance object which might be either
* an appearance stream or an appearance subdictionary.
*/
public PdfDictionary getRolloverAppearanceObject() {
return getAppearanceObject(PdfName.R);
}
/**
* The down appearance is used when the mouse button is pressed or held down within the annotation’s active area.
* If not specified normal appearance is used.
* See also {@link PdfAnnotation#getAppearanceObject(PdfName)}.
*
* @return null if down appearance is not specified or an appearance object which might be either
* an appearance stream or an appearance subdictionary.
*/
public PdfDictionary getDownAppearanceObject() {
return getAppearanceObject(PdfName.D);
}
/**
* Sets a specific type of the appearance. See {@link PdfAnnotation#getAppearanceObject(PdfName)} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearanceType a {@link PdfName} specifying appearance type. Possible types are {@link PdfName#N Normal},
* {@link PdfName#R Rollover} and {@link PdfName#D Down}.
* @param appearance an appearance object which might be either an appearance stream or an appearance subdictionary.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setAppearance(PdfName appearanceType, PdfDictionary appearance) {
PdfDictionary ap = getAppearanceDictionary();
if (ap == null) {
ap = new PdfDictionary();
getPdfObject().put(PdfName.AP, ap);
}
ap.put(appearanceType, appearance);
return this;
}
/**
* Sets normal appearance. See {@link PdfAnnotation#getNormalAppearanceObject()} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearance an appearance object which might be either an appearance stream or an appearance subdictionary.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setNormalAppearance(PdfDictionary appearance) {
return setAppearance(PdfName.N, appearance);
}
/**
* Sets rollover appearance. See {@link PdfAnnotation#getRolloverAppearanceObject()} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearance an appearance object which might be either an appearance stream or an appearance subdictionary.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setRolloverAppearance(PdfDictionary appearance) {
return setAppearance(PdfName.R, appearance);
}
/**
* Sets down appearance. See {@link PdfAnnotation#getDownAppearanceObject()} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearance an appearance object which might be either an appearance stream or an appearance subdictionary.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setDownAppearance(PdfDictionary appearance) {
return setAppearance(PdfName.D, appearance);
}
/**
* Sets a specific type of the appearance using {@link PdfAnnotationAppearance} wrapper.
* This method is used to set only an appearance subdictionary. See {@link PdfAnnotation#getAppearanceObject(PdfName)}
* and {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearanceType a {@link PdfName} specifying appearance type. Possible types are {@link PdfName#N Normal},
* {@link PdfName#R Rollover} and {@link PdfName#D Down}.
* @param appearance an appearance subdictionary wrapped in {@link PdfAnnotationAppearance}.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setAppearance(PdfName appearanceType, PdfAnnotationAppearance appearance) {
return setAppearance(appearanceType, appearance.getPdfObject());
}
/**
* Sets normal appearance using {@link PdfAnnotationAppearance} wrapper. This method is used to set only
* appearance subdictionary. See {@link PdfAnnotation#getNormalAppearanceObject()} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearance an appearance subdictionary wrapped in {@link PdfAnnotationAppearance}.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setNormalAppearance(PdfAnnotationAppearance appearance) {
return setAppearance(PdfName.N, appearance);
}
/**
* Sets rollover appearance using {@link PdfAnnotationAppearance} wrapper. This method is used to set only
* appearance subdictionary. See {@link PdfAnnotation#getRolloverAppearanceObject()} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearance an appearance subdictionary wrapped in {@link PdfAnnotationAppearance}.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setRolloverAppearance(PdfAnnotationAppearance appearance) {
return setAppearance(PdfName.R, appearance);
}
/**
* Sets down appearance using {@link PdfAnnotationAppearance} wrapper. This method is used to set only
* appearance subdictionary. See {@link PdfAnnotation#getDownAppearanceObject()} and
* {@link PdfAnnotation#getAppearanceDictionary()} for more info.
*
* @param appearance an appearance subdictionary wrapped in {@link PdfAnnotationAppearance}.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setDownAppearance(PdfAnnotationAppearance appearance) {
return setAppearance(PdfName.D, appearance);
}
/**
* The annotation’s appearance state, which selects the applicable appearance stream
* from an appearance subdictionary if there is such. See {@link PdfAnnotation#getAppearanceObject(PdfName)}
* for more info.
*
* @return a {@link PdfName} which defines selected appearance state.
*/
public PdfName getAppearanceState() {
return getPdfObject().getAsName(PdfName.AS);
}
/**
* Sets the annotation’s appearance state, which selects the applicable appearance stream
* from an appearance subdictionary. See {@link PdfAnnotation#getAppearanceObject(PdfName)}
* for more info.
*
* @param as a {@link PdfName} which defines appearance state to be selected.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setAppearanceState(PdfName as) {
return put(PdfName.AS, as);
}
/**
* An array specifying the characteristics of the annotation’s border.
* The array consists of three numbers defining the horizontal corner radius,
* vertical corner radius, and border width, all in default user space units.
* If the corner radii are 0, the border has square (not rounded) corners; if
* the border width is 0, no border is drawn.
*
* The array may have a fourth element, an optional dash array (see ISO-320001 8.4.3.6, "Line Dash Pattern").
*
* @return an {@link PdfArray} specifying the characteristics of the annotation’s border.
*/
public PdfArray getBorder() {
return getPdfObject().getAsArray(PdfName.Border);
}
/**
* Sets the characteristics of the annotation’s border.
*
* @param border an {@link PdfAnnotationBorder} specifying the characteristics of the annotation’s border.
* See {@link PdfAnnotation#getBorder()} for more detailes.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setBorder(PdfAnnotationBorder border) {
return put(PdfName.Border, border.getPdfObject());
}
/**
* Sets the characteristics of the annotation’s border.
*
* @param border an {@link PdfArray} specifying the characteristics of the annotation’s border.
* See {@link PdfAnnotation#getBorder()} for more detailes.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setBorder(PdfArray border) {
return put(PdfName.Border, border);
}
/**
* An array of numbers in the range 0.0 to 1.0, representing a colour used for the following purposes:
*
* - The background of the annotation’s icon when closed
*
- The title bar of the annotation’s pop-up window
*
- The border of a link annotation
*
* The number of array elements determines the colour space in which the colour shall be defined:
*
* - 0 - No colour; transparent
*
- 1 - DeviceGray
*
- 3 - DeviceRGB
*
- 4 - DeviceCMYK
*
*
* @return An array of numbers in the range 0.0 to 1.0, representing an annotation colour.
*/
public PdfArray getColorObject() {
return getPdfObject().getAsArray(PdfName.C);
}
/**
* Sets an annotation color. For more details on annotation color purposes and the format
* of the passing {@link PdfArray} see {@link PdfAnnotation#getColorObject()}.
*
* @param color an array of numbers in the range 0.0 to 1.0, specifying color.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setColor(PdfArray color) {
return put(PdfName.C, color);
}
/**
* Sets an annotation color. For more details on annotation color purposes and the format
* of the passing array see {@link PdfAnnotation#getColorObject()}.
*
* @param color an array of numbers in the range 0.0 to 1.0, specifying color.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setColor(float[] color) {
return setColor(new PdfArray(color));
}
/**
* Sets an annotation color. For more details on annotation color purposes
* see {@link PdfAnnotation#getColorObject()}.
*
* @param color {@link Color} object of the either {@link DeviceGray},
* {@link DeviceRgb} or {@link DeviceCmyk} type.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setColor(Color color) {
return setColor(new PdfArray(color.getColorValue()));
}
/**
* The integer key of the annotation’s entry in the structural parent tree
* (see ISO-320001 14.7.4.4, "Finding Structure Elements from Content Items").
*
* @return integer key in structural parent tree or -1 if annotation is not tagged.
*/
public int getStructParentIndex() {
PdfNumber n = getPdfObject().getAsNumber(PdfName.StructParent);
if (n == null)
return -1;
else
return n.intValue();
}
/**
* Sets he integer key of the annotation’s entry in the structural parent tree
* (see ISO-320001 14.7.4.4, "Finding Structure Elements from Content Items").
* Note: Normally, there is no need to take care of this manually, struct parent index is set automatically
* if annotation is added to the tagged document's page.
*
* @param structParentIndex integer which is to be the key of the annotation's entry
* in structural parent tree.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setStructParentIndex(int structParentIndex) {
return put(PdfName.StructParent, new PdfNumber(structParentIndex));
}
/**
* Sets annotation title. This property affects not all annotation types.
*
* @param title a {@link PdfString} which value is to be annotation title.
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setTitle(PdfString title) {
return put(PdfName.T, title);
}
/**
* Annotation title. For example for markup annotations, the title is the text label that shall be displayed in the
* title bar of the annotation’s pop-up window when open and active. For movie annotation Movie actions
* (ISO-320001 12.6.4.9, "Movie Actions") may use this title to reference the movie annotation.
*
* @return {@link PdfString} which value is an annotation title or null if it isn't specified.
*/
public PdfString getTitle() {
return getPdfObject().getAsString(PdfName.T);
}
/**
* The annotation rectangle, defining the location of the annotation on the page in default user space units.
*
* @param array a {@link PdfArray} which specifies a rectangle by two diagonally opposite corners.
* Typically, the array is of form [llx lly urx ury].
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation setRectangle(PdfArray array) {
return put(PdfName.Rect, array);
}
/**
* The annotation rectangle, defining the location of the annotation on the page in default user space units.
*
* @return a {@link PdfArray} which specifies a rectangle by two diagonally opposite corners.
* Typically, the array is of form [llx lly urx ury].
*/
public PdfArray getRectangle() {
return getPdfObject().getAsArray(PdfName.Rect);
}
/**
* PDF 2.0. A language identifier overriding the document’s language identifier to
* specify the natural language for all text in the annotation except where overridden by
* other explicit language specifications
*
* @return the lang entry
*/
public String getLang() {
PdfString lang = getPdfObject().getAsString(PdfName.Lang);
return lang != null ? lang.toUnicodeString() : null;
}
/**
* PDF 2.0. A language identifier overriding the document’s language identifier to
* specify the natural language for all text in the annotation except where overridden by
* other explicit language specifications
*
* @param lang language identifier
* @return this {@link PdfAnnotation} instance
*/
public PdfAnnotation setLang(String lang) {
return put(PdfName.Lang, new PdfString(lang, PdfEncodings.UNICODE_BIG));
}
/**
* PDF 2.0. The blend mode that shall be used when painting the annotation onto the page
*
* @return the blend mode
*/
public PdfName getBlendMode() {
return getPdfObject().getAsName(PdfName.BM);
}
/**
* PDF 2.0. The blend mode that shall be used when painting the annotation onto the page
*
* @param blendMode blend mode
* @return this {@link PdfAnnotation} instance
*/
public PdfAnnotation setBlendMode(PdfName blendMode) {
return put(PdfName.BM, blendMode);
}
/**
* PDF 2.0. When regenerating the annotation's appearance stream, this is the
* opacity value that shall be used for all nonstroking
* operations on all visible elements of the annotation in its closed state (including its
* background and border) but not the popup window that appears when the annotation is
* opened.
*
* @return opacity value for nonstroking operations. Returns 1.0 (default value) if entry is not present
*/
public float getNonStrokingOpacity() {
PdfNumber nonStrokingOpacity = getPdfObject().getAsNumber(PdfName.ca);
return nonStrokingOpacity != null ? nonStrokingOpacity.floatValue() : 1;
}
/**
* PDF 2.0. When regenerating the annotation's appearance stream, this is the
* opacity value that shall be used for all nonstroking
* operations on all visible elements of the annotation in its closed state (including its
* background and border) but not the popup window that appears when the annotation is
* opened.
*
* @param nonStrokingOpacity opacity for nonstroking operations
* @return this {@link PdfAnnotation} instance
*/
public PdfAnnotation setNonStrokingOpacity(float nonStrokingOpacity) {
return put(PdfName.ca, new PdfNumber(nonStrokingOpacity));
}
/**
* PDF 2.0. When regenerating the annotation's appearance stream, this is the
* opacity value that shall be used for stroking all visible
* elements of the annotation in its closed state, including its background and border, but
* not the popup window that appears when the annotation is opened.
*
* @return opacity for stroking operations, including background and border
*/
public float getStrokingOpacity() {
PdfNumber strokingOpacity = getPdfObject().getAsNumber(PdfName.CA);
return strokingOpacity != null ? strokingOpacity.floatValue() : 1;
}
/**
* PDF 2.0. When regenerating the annotation's appearance stream, this is the
* opacity value that shall be used for stroking all visible
* elements of the annotation in its closed state, including its background and border, but
* not the popup window that appears when the annotation is opened.
*
* @param strokingOpacity opacity for stroking operations, including background and border
* @return this {@link PdfAnnotation} object
*/
public PdfAnnotation setStrokingOpacity(float strokingOpacity) {
return put(PdfName.CA, new PdfNumber(strokingOpacity));
}
/**
* Inserts the value into into the underlying {@link PdfDictionary} of this {@link PdfAnnotation} and associates it
* with the specified key. If the key is already present in this {@link PdfAnnotation}, this method will override
* the old value with the specified one.
*
* @param key key to insert or to override
* @param value the value to associate with the specified key
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation put(PdfName key, PdfObject value) {
getPdfObject().put(key, value);
setModified();
return this;
}
/**
* Removes the specified key from the underlying {@link PdfDictionary} of this {@link PdfAnnotation}.
*
* @param key key to be removed
* @return this {@link PdfAnnotation} instance.
*/
public PdfAnnotation remove(PdfName key) {
getPdfObject().remove(key);
return this;
}
/**
*
* Adds file associated with PDF annotation and identifies the relationship between them.
*
* Associated files may be used in Pdf/A-3 and Pdf 2.0 documents.
* The method adds file to array value of the AF key in the annotation dictionary.
*
* For associated files their associated file specification dictionaries shall include the AFRelationship key
*
* @param fs file specification dictionary of associated file
*/
public void addAssociatedFile(PdfFileSpec fs) {
if (null == ((PdfDictionary) fs.getPdfObject()).get(PdfName.AFRelationship)) {
Logger logger = LoggerFactory.getLogger(PdfAnnotation.class);
logger.error(IoLogMessageConstant.ASSOCIATED_FILE_SPEC_SHALL_INCLUDE_AFRELATIONSHIP);
}
PdfArray afArray = getPdfObject().getAsArray(PdfName.AF);
if (afArray == null) {
afArray = new PdfArray();
put(PdfName.AF, afArray);
}
afArray.add(fs.getPdfObject());
}
/**
* Returns files associated with PDF annotation.
*
* @param create defines whether AF arrays will be created if it doesn't exist
* @return associated files array
*/
public PdfArray getAssociatedFiles(boolean create) {
PdfArray afArray = getPdfObject().getAsArray(PdfName.AF);
if (afArray == null && create) {
afArray = new PdfArray();
put(PdfName.AF, afArray);
}
return afArray;
}
/**
* To manually flush a {@code PdfObject} behind this wrapper, you have to ensure
* that this object is added to the document, i.e. it has an indirect reference.
* Basically this means that before flushing you need to explicitly call {@link #makeIndirect(PdfDocument)}.
* For example: wrapperInstance.makeIndirect(document).flush();
* Note that not every wrapper require this, only those that have such warning in documentation.
*/
@Override
public void flush() {
super.flush();
}
@Override
protected boolean isWrappedObjectMustBeIndirect() {
return true;
}
// Created as a private static class in order to facilitate autoport.
static class PdfUnknownAnnotation extends PdfAnnotation {
protected PdfUnknownAnnotation(PdfDictionary pdfObject) {
super(pdfObject);
}
@Override
public PdfName getSubtype() {
return getPdfObject().getAsName(PdfName.Subtype);
}
}
}