Skip to content

Commit 4733e37

Browse files
committed
Implement PDF/UA checks for checkpoint 02: role mapping
DEVSIX-7922
1 parent e0f6081 commit 4733e37

File tree

5 files changed

+357
-3
lines changed

5 files changed

+357
-3
lines changed

pdfua/src/main/java/com/itextpdf/pdfua/checkers/PdfUA1Checker.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,23 @@ This file is part of the iText (R) project.
3131
import com.itextpdf.kernel.pdf.PdfDictionary;
3232
import com.itextpdf.kernel.pdf.PdfDocument;
3333
import com.itextpdf.kernel.pdf.PdfName;
34+
import com.itextpdf.kernel.pdf.PdfObject;
3435
import com.itextpdf.kernel.pdf.PdfResources;
3536
import com.itextpdf.kernel.pdf.PdfStream;
3637
import com.itextpdf.kernel.pdf.tagging.PdfMcr;
38+
import com.itextpdf.kernel.pdf.tagging.PdfNamespace;
39+
import com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot;
40+
import com.itextpdf.kernel.pdf.tagging.StandardRoles;
41+
import com.itextpdf.kernel.pdf.tagutils.IRoleMappingResolver;
42+
import com.itextpdf.kernel.pdf.tagutils.TagStructureContext;
3743
import com.itextpdf.kernel.utils.IValidationChecker;
3844
import com.itextpdf.kernel.utils.ValidationContext;
3945
import com.itextpdf.pdfua.exceptions.PdfUAConformanceException;
4046
import com.itextpdf.pdfua.exceptions.PdfUAExceptionMessageConstants;
4147

4248
import java.util.Collection;
4349
import java.util.HashSet;
50+
import java.util.Map;
4451
import java.util.Set;
4552
import java.util.Stack;
4653

@@ -54,13 +61,16 @@ public class PdfUA1Checker implements IValidationChecker {
5461

5562
private final PdfDocument pdfDocument;
5663

64+
private final TagStructureContext tagStructureContext;
65+
5766
/**
5867
* Creates PdfUA1Checker instance with PDF document which will be validated against PDF/UA-1 standard.
5968
*
6069
* @param pdfDocument the document to validate
6170
*/
6271
public PdfUA1Checker(PdfDocument pdfDocument) {
6372
this.pdfDocument = pdfDocument;
73+
this.tagStructureContext = new TagStructureContext(pdfDocument);
6474
}
6575

6676
/**
@@ -69,6 +79,7 @@ public PdfUA1Checker(PdfDocument pdfDocument) {
6979
@Override
7080
public void validateDocument(ValidationContext validationContext) {
7181
checkCatalog(validationContext.getPdfDocument().getCatalog());
82+
checkStructureTreeRoot(validationContext.getPdfDocument().getStructTreeRoot());
7283
checkFonts(validationContext.getFonts());
7384
}
7485

@@ -107,13 +118,14 @@ private Stack<Tuple2<PdfName, PdfDictionary>> getTagStack(Object data) {
107118
}
108119

109120
private void checkOnOpeningBeginMarkedContent(Object obj, Object extra) {
121+
Tuple2<PdfName, PdfDictionary> currentBmc = (Tuple2<PdfName, PdfDictionary>) extra;
122+
checkStandardRoleMapping(currentBmc);
123+
110124
Stack<Tuple2<PdfName, PdfDictionary>> stack = getTagStack(obj);
111125
if (stack.isEmpty()) {
112126
return;
113127
}
114128

115-
Tuple2<PdfName, PdfDictionary> currentBmc = (Tuple2<PdfName, PdfDictionary>) extra;
116-
117129
boolean isRealContent = isRealContent(currentBmc);
118130
boolean isArtifact = PdfName.Artifact.equals(currentBmc.getFirst());
119131

@@ -125,6 +137,15 @@ private void checkOnOpeningBeginMarkedContent(Object obj, Object extra) {
125137
}
126138
}
127139

140+
private void checkStandardRoleMapping(Tuple2<PdfName, PdfDictionary> tag) {
141+
final PdfNamespace namespace = tagStructureContext.getDocumentDefaultNamespace();
142+
final String role = tag.getFirst().getValue();
143+
if (!StandardRoles.ARTIFACT.equals(role) && !tagStructureContext.checkIfRoleShallBeMappedToStandardRole(role, namespace)) {
144+
throw new PdfUAConformanceException(
145+
MessageFormatUtil.format(PdfUAExceptionMessageConstants.TAG_MAPPING_DOESNT_TERMINATE_WITH_STANDARD_TYPE, role));
146+
}
147+
}
148+
128149
private boolean isInsideArtifact(Stack<Tuple2<PdfName, PdfDictionary>> tagStack) {
129150
for (Tuple2<PdfName, PdfDictionary> tag : tagStack) {
130151
if (PdfName.Artifact.equals(tag.getFirst())) {
@@ -175,6 +196,19 @@ private void checkCatalog(PdfCatalog catalog) {
175196
}
176197
}
177198

199+
private void checkStructureTreeRoot(PdfStructTreeRoot structTreeRoot) {
200+
PdfDictionary roleMap = structTreeRoot.getRoleMap();
201+
for (Map.Entry<PdfName, PdfObject> entry : roleMap.entrySet()) {
202+
final String role = entry.getKey().getValue();
203+
final IRoleMappingResolver roleMappingResolver = pdfDocument.getTagStructureContext()
204+
.getRoleMappingResolver(role);
205+
206+
if (roleMappingResolver.currentRoleIsStandard()) {
207+
throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.ONE_OR_MORE_STANDARD_ROLE_REMAPPED);
208+
}
209+
}
210+
}
211+
178212
private void checkFonts(Collection<PdfFont> fontsInDocument) {
179213
Set<String> fontNamesThatAreNotEmbedded = new HashSet<>();
180214
for (PdfFont font : fontsInDocument) {

pdfua/src/main/java/com/itextpdf/pdfua/exceptions/PdfUAExceptionMessageConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ This file is part of the iText (R) project.
2626
* Class that bundles all the error message templates as constants.
2727
*/
2828
public final class PdfUAExceptionMessageConstants {
29+
public static final String ONE_OR_MORE_STANDARD_ROLE_REMAPPED =
30+
"One or more standard types are remapped.";
2931
public static final String TAG_HASNT_BEEN_ADDED_BEFORE_CONTENT_ADDING =
3032
"Tag hasn't been added before adding content to the canvas.";
3133
public static final String CONTENT_IS_NOT_REAL_CONTENT_AND_NOT_ARTIFACT =
@@ -43,6 +45,8 @@ public final class PdfUAExceptionMessageConstants {
4345
"Tagged content is present inside content marked as Artifact or vice versa.";
4446
public static final String SUSPECTS_ENTRY_IN_MARK_INFO_DICTIONARY_SHALL_NOT_HAVE_A_VALUE_OF_TRUE =
4547
"Suspects entry in mark info dictionary shall not have a value of true.";
48+
public static final String TAG_MAPPING_DOESNT_TERMINATE_WITH_STANDARD_TYPE =
49+
"\"{0}\" tag mapping does not terminate with a standard type.";
4650

4751
private PdfUAExceptionMessageConstants() {
4852
// Empty constructor

pdfua/src/test/java/com/itextpdf/pdfua/PdfUACanvasTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ public void checkPoint_01_005_RectangleMarkedContentWithoutMcid() throws IOExcep
432432
PdfCanvas canvas = new PdfCanvas(pdfDoc.addNewPage());
433433
canvas
434434
.saveState()
435-
.openTag(new CanvasTag(PdfName.Rect))
435+
.openTag(new CanvasTag(PdfName.Art))
436436
.setFillColor(ColorConstants.RED);
437437
Exception e = Assert.assertThrows(PdfUAConformanceException.class, () -> {
438438
canvas.rectangle(new Rectangle(200, 200, 100, 100));

0 commit comments

Comments
 (0)