Skip to content

Commit 9915abb

Browse files
committed
Support PDF A4 checks for actions
DEVSIX-7746
1 parent 580dd26 commit 9915abb

16 files changed

+585
-20
lines changed

pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA2Checker.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -570,16 +570,26 @@ protected void checkForm(PdfDictionary form) {
570570
}
571571
}
572572

573+
574+
/**
575+
* Checks if the catalog is compliant with the PDF/A-2 standard.
576+
*
577+
* @param dict the catalog dictionary
578+
*/
579+
protected void checkCatalogAAConformance(PdfDictionary dict) {
580+
if (dict.containsKey(PdfName.AA)) {
581+
throw new PdfAConformanceException(
582+
PdfAConformanceException.A_CATALOG_DICTIONARY_SHALL_NOT_CONTAIN_AA_ENTRY);
583+
}
584+
}
585+
573586
@Override
574587
protected void checkCatalogValidEntries(PdfDictionary catalogDict) {
575588
if (catalogDict.containsKey(PdfName.NeedsRendering)) {
576589
throw new PdfAConformanceException(PdfAConformanceException.THE_CATALOG_DICTIONARY_SHALL_NOT_CONTAIN_THE_NEEDSRENDERING_KEY);
577590
}
578591

579-
if (catalogDict.containsKey(PdfName.AA)) {
580-
throw new PdfAConformanceException(PdfAConformanceException.A_CATALOG_DICTIONARY_SHALL_NOT_CONTAIN_AA_ENTRY);
581-
}
582-
592+
checkCatalogAAConformance(catalogDict);
583593
if (catalogDict.containsKey(PdfName.Requirements)) {
584594
throw new PdfAConformanceException(PdfAConformanceException.A_CATALOG_DICTIONARY_SHALL_NOT_CONTAIN_REQUIREMENTS_ENTRY);
585595
}
@@ -714,12 +724,20 @@ protected void checkPdfStream(PdfStream stream) {
714724
}
715725
}
716726

717-
@Override
718-
protected void checkPageObject(PdfDictionary pageDict, PdfDictionary pageResources) {
719-
if (pageDict.containsKey(PdfName.AA)) {
727+
/**
728+
* Checks if the page is compliant with the PDF/A-2 standard.
729+
*
730+
* @param dict the page dictionary
731+
*/
732+
protected void checkPageAAConformance(PdfDictionary dict) {
733+
if (dict.containsKey(PdfName.AA)) {
720734
throw new PdfAConformanceException(PdfAConformanceException.THE_PAGE_DICTIONARY_SHALL_NOT_CONTAIN_AA_ENTRY);
721735
}
736+
}
722737

738+
@Override
739+
protected void checkPageObject(PdfDictionary pageDict, PdfDictionary pageResources) {
740+
checkPageAAConformance(pageDict);
723741
if (pageDict.containsKey(PdfName.PresSteps)) {
724742
throw new PdfAConformanceException(PdfAConformanceException.THE_PAGE_DICTIONARY_SHALL_NOT_CONTAIN_PRESSTEPS_ENTRY);
725743
}

pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA4Checker.java

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,29 @@ public class PdfA4Checker extends PdfA3Checker {
103103

104104
private static final Logger LOGGER = LoggerFactory.getLogger(PdfAChecker.class);
105105

106+
107+
private static final Set<PdfName> forbiddenActionsE = Collections
108+
.unmodifiableSet(new HashSet<>(Arrays.asList(
109+
PdfName.Launch,
110+
PdfName.Sound,
111+
PdfName.Movie,
112+
PdfName.ResetForm,
113+
PdfName.ImportData,
114+
PdfName.JavaScript,
115+
PdfName.Hide,
116+
PdfName.Rendition,
117+
PdfName.Trans
118+
)));
119+
private static final Set<PdfName> allowedEntriesInAAWhenNonWidget = Collections
120+
.unmodifiableSet(new HashSet<>(Arrays.asList(
121+
PdfName.E,
122+
PdfName.X,
123+
PdfName.D,
124+
PdfName.U,
125+
PdfName.Fo,
126+
PdfName.Bl
127+
)));
128+
106129
/**
107130
* Creates a PdfA4Checker with the required conformance level
108131
*
@@ -200,6 +223,36 @@ protected void checkPageTransparency(PdfDictionary pageDict, PdfDictionary pageR
200223
}
201224
}
202225

226+
227+
/**
228+
* Check the conformity of the AA dictionary on catalog level.
229+
*
230+
* @param dict the catalog dictionary
231+
*/
232+
@Override
233+
protected void checkCatalogAAConformance(PdfDictionary dict) {
234+
final PdfDictionary aa = dict.getAsDictionary(PdfName.AA);
235+
if (aa != null && hasAAIllegalEntries(aa)) {
236+
throw new PdfAConformanceException(
237+
PdfaExceptionMessageConstant.CATALOG_AA_DICTIONARY_SHALL_CONTAIN_ONLY_ALLOWED_KEYS);
238+
}
239+
}
240+
241+
242+
/**
243+
* Check the conformity of the AA dictionary on catalog level.
244+
*
245+
* @param dict the catalog dictionary
246+
*/
247+
@Override
248+
protected void checkPageAAConformance(PdfDictionary dict) {
249+
final PdfDictionary aa = dict.getAsDictionary(PdfName.AA);
250+
if (aa != null && hasAAIllegalEntries(aa)) {
251+
throw new PdfAConformanceException(
252+
PdfaExceptionMessageConstant.PAGE_AA_DICTIONARY_SHALL_CONTAIN_ONLY_ALLOWED_KEYS);
253+
}
254+
}
255+
203256
//There are no limits for numbers in pdf-a/4
204257
/**
205258
* {@inheritDoc}
@@ -276,6 +329,22 @@ protected Set<PdfName> getAppearanceLessAnnotations() {
276329
return apLessAnnotations;
277330
}
278331

332+
333+
/**
334+
* Check the conformity of the AA dictionary on widget level.
335+
*
336+
* @param dict the widget dictionary
337+
*/
338+
protected void checkWidgetAAConformance(PdfDictionary dict) {
339+
if (!PdfName.Widget.equals(dict.getAsName(PdfName.Subtype)) && dict.containsKey(PdfName.AA)) {
340+
final PdfObject additionalActions = dict.get(PdfName.AA);
341+
if (additionalActions.isDictionary() && hasAAIllegalEntries((PdfDictionary) additionalActions)) {
342+
throw new PdfAConformanceException(
343+
PdfaExceptionMessageConstant.ANNOTATION_AA_DICTIONARY_SHALL_CONTAIN_ONLY_ALLOWED_KEYS);
344+
}
345+
}
346+
}
347+
279348
/**
280349
* {@inheritDoc}
281350
*/
@@ -285,9 +354,27 @@ protected void checkAnnotationAgainstActions(PdfDictionary annotDic) {
285354
throw new PdfAConformanceException(
286355
PdfaExceptionMessageConstant.WIDGET_ANNOTATION_DICTIONARY_OR_FIELD_DICTIONARY_SHALL_NOT_INCLUDE_A_ENTRY);
287356
}
288-
if (!PdfName.Widget.equals(annotDic.getAsName(PdfName.Subtype)) && annotDic.containsKey(PdfName.AA)) {
289-
throw new PdfAConformanceException(PdfAConformanceException.AN_ANNOTATION_DICTIONARY_SHALL_NOT_CONTAIN_AA_KEY);
357+
checkWidgetAAConformance(annotDic);
358+
}
359+
360+
private static boolean hasAAIllegalEntries(PdfDictionary aa) {
361+
for (final PdfName key : aa.keySet()) {
362+
if (!allowedEntriesInAAWhenNonWidget.contains(key)) {
363+
return true;
364+
}
365+
}
366+
return false;
367+
}
368+
369+
/**
370+
* {@inheritDoc}
371+
*/
372+
@Override
373+
protected Set<PdfName> getForbiddenActions() {
374+
if ("E".equals(conformanceLevel.getConformance())) {
375+
return forbiddenActionsE;
290376
}
377+
return super.getForbiddenActions();
291378
}
292379

293380
/**

pdfa/src/main/java/com/itextpdf/pdfa/exceptions/PdfaExceptionMessageConstant.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ public final class PdfaExceptionMessageConstant {
3838
= "Can't find an appropriate checker for a specified name.";
3939
public static final String FILE_SPECIFICATION_DICTIONARY_SHALL_CONTAIN_AFRELATIONSHIP_KEY = "Each embedded file’s file specification dictionary shall contain an AFRelationship key.";
4040
public static final String WIDGET_ANNOTATION_DICTIONARY_OR_FIELD_DICTIONARY_SHALL_NOT_INCLUDE_A_ENTRY = "Widget annotation dictionary or field dictionary shall not include a entry";
41+
public static final String ANNOTATION_AA_DICTIONARY_SHALL_CONTAIN_ONLY_ALLOWED_KEYS =
42+
"If annotation dictionary (other than a Widget "
43+
+ "annotation dictionary) includes an AA entry, its value (which is an additional-actions "
44+
+ "dictionary) shall only contain keys from the following list: E, X, D, U, Fo, and B";
45+
public static final String CATALOG_AA_DICTIONARY_SHALL_CONTAIN_ONLY_ALLOWED_KEYS =
46+
"If a document catalog dictionary includes an AA entry, its value (which is an additional-actions "
47+
+ "dictionary) shall only contain keys from the following list: E, X, D, U, Fo, and B";
48+
public static final String PAGE_AA_DICTIONARY_SHALL_CONTAIN_ONLY_ALLOWED_KEYS =
49+
"If page dictionary includes an AA entry, its value (which is an additional-actions "
50+
+ "dictionary) shall only contain keys from the following list: E, X, D, U, Fo, and B";
51+
4152

4253
public static final String THE_DOCUMENT_AND_THE_PAGE_DO_NOT_CONTAIN_A_PDFA_OUTPUTINTENT_BUT_PAGE_CONTAINS_TRANSPARENCY_AND_DOES_NOT_CONTAIN_BLENDING_COLOR_SPACE =
4354
"If the document does not contain a PDF/A output intent, then all pages that contain transparency shall"

0 commit comments

Comments
 (0)