org.verapdf.model.impl.pb.pd.PBoxPDAnnot Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdfbox-validation-model Show documentation
Show all versions of pdfbox-validation-model Show documentation
Java PDF Box implementation for the veraPDF Validation Java API, generated from an Xtext model.
/**
* This file is part of veraPDF PDF Box PDF/A Validation Model Implementation, a module of the veraPDF project.
* Copyright (c) 2015, veraPDF Consortium
* All rights reserved.
*
* veraPDF PDF Box PDF/A Validation Model Implementation is free software: you can redistribute it and/or modify
* it under the terms of either:
*
* The GNU General public license GPLv3+.
* You should have received a copy of the GNU General Public License
* along with veraPDF PDF Box PDF/A Validation Model Implementation as the LICENSE.GPL file in the root of the source
* tree. If not, see http://www.gnu.org/licenses/ or
* https://www.gnu.org/licenses/gpl-3.0.en.html.
*
* The Mozilla Public License MPLv2+.
* You should have received a copy of the Mozilla Public License along with
* veraPDF PDF Box PDF/A Validation Model Implementation as the LICENSE.MPL file in the root of the source tree.
* If a copy of the MPL was not distributed with this file, you can obtain one at
* http://mozilla.org/MPL/2.0/.
*/
package org.verapdf.model.impl.pb.pd;
import org.apache.pdfbox.cos.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDNumberTreeNode;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDParentTreeValue;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory;
import org.apache.pdfbox.pdmodel.interactive.action.PDAnnotationAdditionalActions;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceEntry;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.verapdf.model.baselayer.Object;
import org.verapdf.model.coslayer.CosBM;
import org.verapdf.model.coslayer.CosLang;
import org.verapdf.model.impl.pb.cos.PBCosBM;
import org.verapdf.model.impl.pb.cos.PBCosLang;
import org.verapdf.model.impl.pb.pd.actions.PBoxPDAction;
import org.verapdf.model.impl.pb.pd.actions.PBoxPDAnnotationAdditionalActions;
import org.verapdf.model.impl.pb.pd.annotations.PBoxPD3DAnnot;
import org.verapdf.model.impl.pb.pd.annotations.PBoxPDLinkAnnot;
import org.verapdf.model.impl.pb.pd.annotations.PBoxPDPrinterMarkAnnot;
import org.verapdf.model.impl.pb.pd.annotations.PBoxPDTrapNetAnnot;
import org.verapdf.model.impl.pb.pd.annotations.PBoxPDWidgetAnnot;
import org.verapdf.model.impl.pb.pd.images.PBoxPDXForm;
import org.verapdf.model.pdlayer.*;
import org.verapdf.model.tools.resources.PDInheritableResources;
import org.verapdf.pdfa.flavours.PDFAFlavour;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Evgeniy Muravitskiy
*/
public class PBoxPDAnnot extends PBoxPDObject implements PDAnnot {
public static final String ANNOTATION_TYPE = "PDAnnot";
public static final String DICT = "Dict";
public static final String STREAM = "Stream";
public static final String APPEARANCE = "appearance";
public static final String C = "C";
public static final String IC = "IC";
public static final String A = "A";
public static final String ADDITIONAL_ACTION = "AA";
public static final String LANG = "Lang";
public static final String LINK = "Link";
public static final String PRINTER_MARK = "PrinterMark";
public static final String WIDGET = "Widget";
public static final String TRAP_NET = "TrapNet";
public static final String TYPE_3D = "3D";
public static final String BM = "BM";
public static final int X_AXIS = 0;
public static final int Y_AXIS = 1;
private final PDResources pageResources;
private final boolean isFKeyPresent;
private final String subtype;
private final String ap;
private final int annotationFlag;
private final Double ca;
private final String nType;
private final String ft;
private final Double width;
private final Double height;
private final PDDocument document;
private final PDFAFlavour flavour;
private final PDPage pdPage;
private List appearance = null;
private List blendMode = null;
private boolean containsTransparency = false;
public PBoxPDAnnot(PDAnnotation annot, PDResources pageResources, PDDocument document, PDFAFlavour flavour, String type, PDPage pdPage) {
super(annot, type);
this.pageResources = pageResources;
this.subtype = annot.getSubtype();
this.ap = getAP(annot);
COSDictionary annotDict = annot.getCOSObject();
this.isFKeyPresent = annotDict.containsKey(COSName.F);
this.annotationFlag = annot.getAnnotationFlags();
this.ca = PBoxPDAnnot.getCA(annot);
this.nType = getN_type(annot);
this.ft = PBoxPDAnnot.getFT(annot);
this.width = PBoxPDAnnot.getWidth(annot);
this.height = PBoxPDAnnot.getHeight(annot);
this.document = document;
this.flavour = flavour;
this.pdPage = pdPage;
}
public PBoxPDAnnot(PDAnnotation annot, PDResources pageResources, PDDocument document, PDFAFlavour flavour, PDPage pdPage) {
this(annot, pageResources, document, flavour, ANNOTATION_TYPE, pdPage);
}
private static String getAP(PDAnnotation annot) {
COSBase apLocal = annot.getCOSObject().getDictionaryObject(COSName.AP);
if (apLocal instanceof COSDictionary) {
return ((COSDictionary) apLocal).keySet().stream().map(COSName::getName).collect(Collectors.joining("&"));
}
return null;
}
private static Double getCA(PDAnnotation annot) {
COSBase caLocal = annot.getCOSObject().getDictionaryObject(COSName.CA);
return !(caLocal instanceof COSNumber) ? null : ((COSNumber) caLocal).doubleValue();
}
private static String getN_type(PDAnnotation annot) {
PDAppearanceDictionary appearanceDictionary = annot.getAppearance();
if (appearanceDictionary != null) {
PDAppearanceEntry normalAppearance = appearanceDictionary.getNormalAppearance();
if (normalAppearance == null) {
return null;
} else if (normalAppearance.isSubDictionary()) {
return DICT;
} else {
return STREAM;
}
}
return null;
}
private static String getFT(PDAnnotation annot) {
Set visitedKeys = new HashSet<>();
COSBase curr = annot.getCOSObject();
while (curr instanceof COSDictionary) {
COSDictionary currDict = (COSDictionary) curr;
COSObjectKey key = currDict.getKey();
if (key != null) {
if (visitedKeys.contains(key)) {
return null;
}
visitedKeys.add(key);
}
if (currDict.containsKey(COSName.FT)) {
return currDict.getNameAsString(COSName.FT);
}
curr = currDict.getItem(COSName.PARENT);
if (curr instanceof COSObject) {
curr = ((COSObject) curr).getObject();
}
}
return null;
}
private static Double getWidth(PDAnnotation annot) {
return PBoxPDAnnot.getDifference(annot, X_AXIS);
}
private static Double getHeight(PDAnnotation annot) {
return PBoxPDAnnot.getDifference(annot, Y_AXIS);
}
private static Double getDifference(PDAnnotation annot, int shift) {
COSBase array = annot.getCOSObject().getDictionaryObject(COSName.RECT);
if (array instanceof COSArray && ((COSArray) array).size() == 4) {
COSBase less = ((COSArray) array).getObject(shift);
COSBase great = ((COSArray) array).getObject(2 + shift);
if (less instanceof COSNumber && great instanceof COSNumber) {
return ((COSNumber) great).doubleValue() - ((COSNumber) less).doubleValue();
}
}
return null;
}
public PDResources getPageResources() {
return pageResources;
}
@Override
public String getSubtype() {
return this.subtype;
}
@Override
public String getAP() {
return this.ap;
}
@Override
public Long getF() {
return isFKeyPresent ? Long.valueOf(this.annotationFlag) : null;
}
@Override
public Double getCA() {
return this.ca;
}
@Override
public String getN_type() {
return this.nType;
}
@Override
public Boolean getcontainsC() {
COSBase colorArray = ((PDAnnotation) this.simplePDObject).getCOSObject().getDictionaryObject(COSName.C);
return colorArray instanceof COSArray;
}
@Override
public Boolean getcontainsIC() {
COSBase colorArray = ((PDAnnotation) this.simplePDObject).getCOSObject().getDictionaryObject(COSName.IC);
return colorArray instanceof COSArray;
}
@Override
public String getFT() {
return this.ft;
}
@Override
public Double getwidth() {
return this.width;
}
@Override
public Double getheight() {
return this.height;
}
@Override
public Boolean getcontainsAA() {
COSBase pageObject = this.simplePDObject.getCOSObject();
return pageObject instanceof COSDictionary &&
((COSDictionary) pageObject).containsKey(COSName.AA);
}
@Override
public String getstructParentType() {
PDStructureTreeRoot structTreeRoot = this.document.getDocumentCatalog().getStructureTreeRoot();
int structParent = ((PDAnnotation)this.simplePDObject).getStructParent();
if (structTreeRoot != null) {
PDNumberTreeNode parentTreeRoot = structTreeRoot.getParentTree();
COSBase structureElement = null;
try {
PDParentTreeValue treeValue = parentTreeRoot != null ? (PDParentTreeValue)parentTreeRoot.getValue(structParent) : null;
if (treeValue != null) {
structureElement = treeValue.getCOSObject();
}
} catch (IOException var6) {
return null;
}
if (structureElement != null && structureElement instanceof COSDictionary) {
return ((COSDictionary)structureElement).getNameAsString(COSName.S);
}
}
return null;
}
@Override
public String getstructParentStandardType() {
return null;
}
@Override
public String getstructParentObjectKey() {
return null;
}
private List getLang() {
PDStructureTreeRoot structTreeRoot = this.document.getDocumentCatalog().getStructureTreeRoot();
int structParent = ((PDAnnotation) this.simplePDObject).getStructParent();
if (structTreeRoot != null && structParent != 0) {
PDNumberTreeNode parentTreeRoot = structTreeRoot.getParentTree();
COSBase structureElement;
try {
PDParentTreeValue treeValue = parentTreeRoot == null ? null : (PDParentTreeValue) parentTreeRoot.getValue(structParent);
structureElement = treeValue == null ? null : treeValue.getCOSObject();
} catch (IOException e) {
return Collections.emptyList();
}
if (structureElement instanceof COSDictionary) {
String lang = ((COSDictionary) structureElement).getNameAsString(COSName.LANG);
if (lang != null) {
List list = new ArrayList<>(MAX_NUMBER_OF_ELEMENTS);
list.add(new PBCosLang(new COSString(lang)));
return Collections.unmodifiableList(list);
}
}
}
return Collections.emptyList();
}
@Override
public String getContents() {
return ((PDAnnotation) simplePDObject).getContents();
}
@Override
public String getAlt() {
PDStructureTreeRoot structTreeRoot = this.document.getDocumentCatalog().getStructureTreeRoot();
int structParent = ((PDAnnotation) this.simplePDObject).getStructParent();
if (structTreeRoot != null && structParent != 0) {
PDNumberTreeNode parentTreeRoot = structTreeRoot.getParentTree();
COSBase structureElement;
try {
PDParentTreeValue treeValue = parentTreeRoot == null ? null : (PDParentTreeValue) parentTreeRoot.getValue(structParent);
structureElement = treeValue == null ? null : treeValue.getCOSObject();
} catch (IOException e) {
return null;
}
if (structureElement instanceof COSDictionary) {
return ((COSDictionary) structureElement).getNameAsString(COSName.ALT);
}
}
return null;
}
@Override
public Boolean getisOutsideCropBox() {
PDRectangle cropBox = pdPage.getCropBox();
PDRectangle rectangle = ((PDAnnotation) simplePDObject).getRectangle();
if (rectangle != null) {
return cropBox.getLowerLeftY() >= rectangle.getUpperRightY() || cropBox.getLowerLeftX() >= rectangle.getUpperRightX()
|| cropBox.getUpperRightY() <= rectangle.getLowerLeftY() || cropBox.getUpperRightX() <= rectangle.getLowerLeftX();
}
return null;
}
@Override
public Boolean getcontainsA() {
COSBase pageObject = this.simplePDObject.getCOSObject();
return pageObject instanceof COSDictionary && ((COSDictionary) pageObject).containsKey(COSName.A);
}
@Override
public Boolean getisArtifact() {
return null;
}
@Override
public List extends Object> getLinkedObjects(String link) {
switch (link) {
case ADDITIONAL_ACTION:
return this.getAdditionalActions();
case A:
return this.getA();
case APPEARANCE:
return this.getAppearance();
case LANG:
return this.getLang();
case BM:
return this.getBM();
default:
return super.getLinkedObjects(link);
}
}
private List getBM() {
if (this.blendMode == null) {
this.blendMode = parseBM();
}
return this.blendMode;
}
private List parseBM() {
COSBase BM = ((COSDictionary)simplePDObject.getCOSObject()).getDictionaryObject(COSName.BM);
if (BM == null || flavour == null || flavour.getPart() != PDFAFlavour.Specification.ISO_19005_4) {
return Collections.emptyList();
}
if (BM instanceof COSName) {
this.containsTransparency = true;
List list = new ArrayList<>(MAX_NUMBER_OF_ELEMENTS);
list.add(new PBCosBM((COSName)BM));
return Collections.unmodifiableList(list);
}
return Collections.emptyList();
}
protected List getAdditionalActions() {
COSBase actionDictionary = ((PDAnnotation) simplePDObject).getCOSObject().getDictionaryObject(COSName.AA);
if (actionDictionary instanceof COSDictionary && ((COSDictionary) actionDictionary).size() != 0) {
List actions = new ArrayList<>(MAX_NUMBER_OF_ELEMENTS);
PDAnnotationAdditionalActions additionalActions = new PDAnnotationAdditionalActions(
(COSDictionary) actionDictionary);
actions.add(new PBoxPDAnnotationAdditionalActions(additionalActions));
return Collections.unmodifiableList(actions);
}
return Collections.emptyList();
}
private List getA() {
COSBase actionDictionary = ((PDAnnotation) this.simplePDObject).getCOSObject().getDictionaryObject(COSName.A);
if (actionDictionary instanceof COSDictionary) {
org.apache.pdfbox.pdmodel.interactive.action.PDAction action = PDActionFactory
.createAction((COSDictionary) actionDictionary);
PDAction result = PBoxPDAction.getAction(action);
if (result != null) {
List actions = new ArrayList<>(MAX_NUMBER_OF_ELEMENTS);
actions.add(result);
return Collections.unmodifiableList(actions);
}
}
return Collections.emptyList();
}
/**
* @return normal appearance stream (N key in the appearance dictionary) of
* the annotation
*/
private List getAppearance() {
if (this.appearance == null) {
parseAppearance();
}
return this.appearance;
}
boolean isContainsTransparency() {
if (this.appearance == null) {
parseAppearance();
}
if (this.blendMode == null) {
this.blendMode = parseBM();
}
return this.containsTransparency;
}
private void parseAppearance() {
PDAppearanceDictionary appearanceDictionary = ((PDAnnotation) this.simplePDObject).getAppearance();
if (appearanceDictionary != null) {
COSDictionary dictionary = appearanceDictionary.getCOSObject();
COSBase normalAppearanceBase = dictionary.getDictionaryObject(COSName.N);
COSBase downAppearanceBase = dictionary.getDictionaryObject(COSName.D);
COSBase rolloverAppearanceBase = dictionary.getDictionaryObject(COSName.R);
if (normalAppearanceBase != null || downAppearanceBase != null || rolloverAppearanceBase != null) {
List appearances = new ArrayList<>();
addContentStreamsFromAppearanceEntry(normalAppearanceBase, appearances);
addContentStreamsFromAppearanceEntry(downAppearanceBase, appearances);
addContentStreamsFromAppearanceEntry(rolloverAppearanceBase, appearances);
this.appearance = Collections.unmodifiableList(appearances);
} else {
this.appearance = Collections.emptyList();
}
} else {
this.appearance = Collections.emptyList();
}
}
private void addContentStreamsFromAppearanceEntry(COSBase appearanceEntry, List appearances) {
if (appearanceEntry != null) {
PDAppearanceEntry newAppearance = new PDAppearanceEntry(appearanceEntry);
if (newAppearance.isStream()) {
addAppearance(appearances, newAppearance.getAppearanceStream());
} else {
Map subDictionary = newAppearance.getSubDictionary();
for (PDAppearanceStream stream : subDictionary.values()) {
addAppearance(appearances, stream);
}
}
}
}
private void addAppearance(List list, PDAppearanceStream toAdd) {
if (toAdd != null) {
PDInheritableResources resources = PDInheritableResources.getInstance(this.pageResources,
toAdd.getResources());
PBoxPDXForm xForm = new PBoxPDXForm(toAdd, resources, this.document, this.flavour);
this.containsTransparency |= xForm.containsTransparency();
list.add(xForm);
}
}
public static PBoxPDAnnot createAnnot(PDAnnotation annot, PDResources pageResources, PDDocument document, PDFAFlavour flavour, PDPage pdPage) {
String subtype = annot.getSubtype();
if (subtype == null) {
return new PBoxPDAnnot(annot, pageResources, document, flavour, pdPage);
}
switch (subtype) {
case WIDGET:
return new PBoxPDWidgetAnnot(annot, pageResources, document, flavour, pdPage);
case TYPE_3D:
return new PBoxPD3DAnnot(annot, pageResources, document, flavour, pdPage);
case TRAP_NET:
return new PBoxPDTrapNetAnnot(annot, pageResources, document, flavour, pdPage);
case LINK:
return new PBoxPDLinkAnnot(annot, pageResources, document, flavour, pdPage);
case PRINTER_MARK:
return new PBoxPDPrinterMarkAnnot(annot, pageResources, document, flavour, pdPage);
default:
return new PBoxPDAnnot(annot, pageResources, document, flavour, pdPage);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy