Skip to content

Commit 2914ea8

Browse files
committed
Check Output intents and colorspaces
DEVSIX-7775
1 parent c42dc7d commit 2914ea8

32 files changed

+1460
-118
lines changed

pdfa/src/main/java/com/itextpdf/pdfa/PdfADocument.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,17 @@ public PdfAConformanceLevel getConformanceLevel() {
234234
}
235235
}
236236

237+
/**
238+
* {@inheritDoc}
239+
*
240+
* @param outputIntent {@inheritDoc}
241+
*/
242+
@Override
243+
public void addOutputIntent(PdfOutputIntent outputIntent) {
244+
super.addOutputIntent(outputIntent);
245+
checker.setPdfAOutputIntentColorSpace(getCatalog().getPdfObject());
246+
}
247+
237248
void logThatPdfAPageFlushingWasNotPerformed() {
238249
if (!alreadyLoggedThatPageFlushingWasNotPerformed) {
239250
alreadyLoggedThatPageFlushingWasNotPerformed = true;

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

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void checkInlineImage(PdfStream inlineImage, PdfDictionary currentColorSp
155155

156156
@Override
157157
public void checkColor(Color color, PdfDictionary currentColorSpaces, Boolean fill, PdfStream stream) {
158-
checkColorSpace(color.getColorSpace(), currentColorSpaces, true, fill);
158+
checkColorSpace(color.getColorSpace(), stream, currentColorSpaces, true, fill);
159159
if (color instanceof PatternColor) {
160160
PdfPattern pattern = ((PatternColor) color).getPattern();
161161
if (pattern instanceof PdfPattern.Tiling) {
@@ -164,8 +164,12 @@ public void checkColor(Color color, PdfDictionary currentColorSpaces, Boolean fi
164164
}
165165
}
166166

167+
/**
168+
* {@inheritDoc}
169+
*/
167170
@Override
168-
public void checkColorSpace(PdfColorSpace colorSpace, PdfDictionary currentColorSpaces, boolean checkAlternate, Boolean fill) {
171+
public void checkColorSpace(PdfColorSpace colorSpace, PdfObject pdfObject, PdfDictionary currentColorSpaces,
172+
boolean checkAlternate, Boolean fill) {
169173
if (colorSpace instanceof PdfSpecialCs.Separation) {
170174
colorSpace = ((PdfSpecialCs.Separation) colorSpace).getBaseCs();
171175
} else if (colorSpace instanceof PdfSpecialCs.DeviceN) {
@@ -179,17 +183,17 @@ public void checkColorSpace(PdfColorSpace colorSpace, PdfDictionary currentColor
179183
}
180184

181185
if (colorSpace instanceof PdfDeviceCs.Rgb) {
182-
if (cmykIsUsed) {
186+
if (cmykIsUsed || !cmykUsedObjects.isEmpty()) {
183187
throw new PdfAConformanceException(PdfaExceptionMessageConstant.DEVICERGB_AND_DEVICECMYK_COLORSPACES_CANNOT_BE_USED_BOTH_IN_ONE_FILE);
184188
}
185-
rgbIsUsed = true;
189+
rgbUsedObjects.add(pdfObject);
186190
} else if (colorSpace instanceof PdfDeviceCs.Cmyk) {
187-
if (rgbIsUsed) {
191+
if (rgbIsUsed || !rgbUsedObjects.isEmpty()) {
188192
throw new PdfAConformanceException(PdfaExceptionMessageConstant.DEVICERGB_AND_DEVICECMYK_COLORSPACES_CANNOT_BE_USED_BOTH_IN_ONE_FILE);
189193
}
190-
cmykIsUsed = true;
194+
cmykUsedObjects.add(pdfObject);
191195
} else if (colorSpace instanceof PdfDeviceCs.Gray) {
192-
grayIsUsed = true;
196+
grayUsedObjects.add(pdfObject);
193197
}
194198
}
195199

@@ -216,18 +220,30 @@ protected long getMaxNumberOfIndirectObjects() {
216220
return 8_388_607;
217221
}
218222

223+
/**
224+
* {@inheritDoc}
225+
*/
219226
@Override
220227
protected void checkColorsUsages() {
221-
if ((rgbIsUsed || cmykIsUsed || grayIsUsed) && pdfAOutputIntentColorSpace == null) {
228+
// Do not check anything here. All checks are in checkPageColorsUsages.
229+
}
230+
231+
/**
232+
* {@inheritDoc}
233+
*/
234+
@Override
235+
protected void checkPageColorsUsages(PdfDictionary pageDict, PdfDictionary pageResources) {
236+
if ((rgbIsUsed || cmykIsUsed || grayIsUsed || !rgbUsedObjects.isEmpty() || !cmykUsedObjects.isEmpty() ||
237+
grayUsedObjects.isEmpty()) && pdfAOutputIntentColorSpace == null) {
222238
throw new PdfAConformanceException(PdfaExceptionMessageConstant.IF_DEVICE_RGB_CMYK_GRAY_USED_IN_FILE_THAT_FILE_SHALL_CONTAIN_PDFA_OUTPUTINTENT);
223239
}
224240

225-
if (rgbIsUsed) {
241+
if (rgbIsUsed || !rgbUsedObjects.isEmpty()) {
226242
if (!ICC_COLOR_SPACE_RGB.equals(pdfAOutputIntentColorSpace)) {
227243
throw new PdfAConformanceException(PdfaExceptionMessageConstant.DEVICERGB_MAY_BE_USED_ONLY_IF_THE_FILE_HAS_A_RGB_PDFA_OUTPUT_INTENT);
228244
}
229245
}
230-
if (cmykIsUsed) {
246+
if (cmykIsUsed || !cmykUsedObjects.isEmpty()) {
231247
if (!ICC_COLOR_SPACE_CMYK.equals(pdfAOutputIntentColorSpace)) {
232248
throw new PdfAConformanceException(PdfaExceptionMessageConstant.DEVICECMYK_MAY_BE_USED_ONLY_IF_THE_FILE_HAS_A_CMYK_PDFA_OUTPUT_INTENT);
233249
}
@@ -377,13 +393,13 @@ protected void checkImage(PdfStream image, PdfDictionary currentColorSpaces) {
377393
PdfColorSpace colorSpace = null;
378394
if (isAlreadyChecked(image)) {
379395
colorSpace = checkedObjectsColorspace.get(image);
380-
checkColorSpace(colorSpace, currentColorSpaces, true, null);
396+
checkColorSpace(colorSpace, image, currentColorSpaces, true, null);
381397
return;
382398
}
383399
PdfObject colorSpaceObj = image.get(PdfName.ColorSpace);
384400
if (colorSpaceObj != null) {
385401
colorSpace = PdfColorSpace.makeColorSpace(colorSpaceObj);
386-
checkColorSpace(colorSpace, currentColorSpaces, true, null);
402+
checkColorSpace(colorSpace, image, currentColorSpaces, true, null);
387403
checkedObjectsColorspace.put(image, colorSpace);
388404
}
389405

@@ -427,7 +443,7 @@ protected void checkFormXObject(PdfStream form) {
427443
throw new PdfAConformanceException(PdfaExceptionMessageConstant.A_GROUP_OBJECT_WITH_AN_S_KEY_WITH_A_VALUE_OF_TRANSPARENCY_SHALL_NOT_BE_INCLUDED_IN_A_FORM_XOBJECT);
428444
}
429445

430-
checkResources(form.getAsDictionary(PdfName.Resources));
446+
checkResources(form.getAsDictionary(PdfName.Resources), form);
431447
checkContentStream(form);
432448
}
433449

@@ -674,7 +690,7 @@ protected void checkForm(PdfDictionary form) {
674690
throw new PdfAConformanceException(PdfaExceptionMessageConstant.NEEDAPPEARANCES_FLAG_OF_THE_INTERACTIVE_FORM_DICTIONARY_SHALL_EITHER_NOT_BE_PRESENTED_OR_SHALL_BE_FALSE);
675691
}
676692

677-
checkResources(form.getAsDictionary(PdfName.DR));
693+
checkResources(form.getAsDictionary(PdfName.DR), form);
678694

679695
PdfArray fields = form.getAsArray(PdfName.Fields);
680696
if (fields != null) {
@@ -684,7 +700,7 @@ protected void checkForm(PdfDictionary form) {
684700
if (fieldDic.containsKey(PdfName.A) || fieldDic.containsKey(PdfName.AA)) {
685701
throw new PdfAConformanceException(PdfaExceptionMessageConstant.WIDGET_ANNOTATION_DICTIONARY_OR_FIELD_DICTIONARY_SHALL_NOT_INCLUDE_A_OR_AA_ENTRY);
686702
}
687-
checkResources(fieldDic.getAsDictionary(PdfName.DR));
703+
checkResources(fieldDic.getAsDictionary(PdfName.DR), fieldDic);
688704
}
689705
}
690706
}

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

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public void checkColor(Color color, PdfDictionary currentColorSpaces, Boolean fi
218218
if (pattern instanceof PdfPattern.Shading) {
219219
PdfDictionary shadingDictionary = ((PdfPattern.Shading) pattern).getShading();
220220
PdfObject colorSpace = shadingDictionary.get(PdfName.ColorSpace);
221-
checkColorSpace(PdfColorSpace.makeColorSpace(colorSpace), currentColorSpaces, true, true);
221+
checkColorSpace(PdfColorSpace.makeColorSpace(colorSpace), contentStream, currentColorSpaces, true, true);
222222
final PdfDictionary extGStateDict = ((PdfDictionary) pattern.getPdfObject()).getAsDictionary(PdfName.ExtGState);
223223
CanvasGraphicsState gState = new UpdateCanvasGraphicsState(extGStateDict);
224224
checkExtGState(gState, contentStream);
@@ -230,8 +230,12 @@ public void checkColor(Color color, PdfDictionary currentColorSpaces, Boolean fi
230230
super.checkColor(color, currentColorSpaces, fill, contentStream);
231231
}
232232

233+
/**
234+
* {@inheritDoc}
235+
*/
233236
@Override
234-
public void checkColorSpace(PdfColorSpace colorSpace, PdfDictionary currentColorSpaces, boolean checkAlternate, Boolean fill) {
237+
public void checkColorSpace(PdfColorSpace colorSpace, PdfObject pdfObject, PdfDictionary currentColorSpaces,
238+
boolean checkAlternate, Boolean fill) {
235239
if (fill != null) {
236240
if ((boolean) fill) {
237241
currentFillCsIsIccBasedCMYK = false;
@@ -245,7 +249,7 @@ public void checkColorSpace(PdfColorSpace colorSpace, PdfDictionary currentColor
245249
PdfSpecialCs.Separation separation = (PdfSpecialCs.Separation) colorSpace;
246250
checkSeparationCS((PdfArray) separation.getPdfObject());
247251
if (checkAlternate) {
248-
checkColorSpace(separation.getBaseCs(), currentColorSpaces, false, fill);
252+
checkColorSpace(separation.getBaseCs(), pdfObject, currentColorSpaces, false, fill);
249253
}
250254

251255
} else if (colorSpace instanceof PdfSpecialCs.DeviceN) {
@@ -266,30 +270,30 @@ public void checkColorSpace(PdfColorSpace colorSpace, PdfDictionary currentColor
266270
}
267271

268272
if (checkAlternate) {
269-
checkColorSpace(deviceN.getBaseCs(), currentColorSpaces, false, fill);
273+
checkColorSpace(deviceN.getBaseCs(), pdfObject, currentColorSpaces, false, fill);
270274
}
271275

272276
} else if (colorSpace instanceof PdfSpecialCs.Indexed) {
273277
if (checkAlternate) {
274-
checkColorSpace(((PdfSpecialCs.Indexed) colorSpace).getBaseCs(), currentColorSpaces, true, fill);
278+
checkColorSpace(((PdfSpecialCs.Indexed) colorSpace).getBaseCs(), pdfObject, currentColorSpaces, true, fill);
275279
}
276280
} else if (colorSpace instanceof PdfSpecialCs.UncoloredTilingPattern) {
277281
if (checkAlternate) {
278-
checkColorSpace(((PdfSpecialCs.UncoloredTilingPattern) colorSpace).getUnderlyingColorSpace(), currentColorSpaces, true, fill);
282+
checkColorSpace(((PdfSpecialCs.UncoloredTilingPattern) colorSpace).getUnderlyingColorSpace(), pdfObject,
283+
currentColorSpaces, true, fill);
279284
}
280285
} else {
281-
282286
if (colorSpace instanceof PdfDeviceCs.Rgb) {
283-
if (!checkDefaultCS(currentColorSpaces, fill, PdfName.DefaultRGB, 3)) {
284-
rgbIsUsed = true;
287+
if (!checkDefaultCS(pdfObject, currentColorSpaces, fill, PdfName.DefaultRGB, 3)) {
288+
rgbUsedObjects.add(pdfObject);
285289
}
286290
} else if (colorSpace instanceof PdfDeviceCs.Cmyk) {
287-
if (!checkDefaultCS(currentColorSpaces, fill, PdfName.DefaultCMYK, 4)) {
288-
cmykIsUsed = true;
291+
if (!checkDefaultCS(pdfObject, currentColorSpaces, fill, PdfName.DefaultCMYK, 4)) {
292+
cmykUsedObjects.add(pdfObject);
289293
}
290294
} else if (colorSpace instanceof PdfDeviceCs.Gray) {
291-
if (!checkDefaultCS(currentColorSpaces, fill, PdfName.DefaultGray, 1)) {
292-
grayIsUsed = true;
295+
if (!checkDefaultCS(pdfObject, currentColorSpaces, fill, PdfName.DefaultGray, 1)) {
296+
grayUsedObjects.add(pdfObject);
293297
}
294298
}
295299
}
@@ -544,7 +548,7 @@ protected void checkAppearanceStream(PdfStream appearanceStream) {
544548
if (isContainsTransparencyGroup(appearanceStream)) {
545549
this.transparencyObjects.add(appearanceStream);
546550
}
547-
checkResources(appearanceStream.getAsDictionary(PdfName.Resources));
551+
checkResources(appearanceStream.getAsDictionary(PdfName.Resources), appearanceStream);
548552
}
549553

550554
@Override
@@ -557,14 +561,14 @@ protected void checkForm(PdfDictionary form) {
557561
if (form.containsKey(PdfName.XFA)) {
558562
throw new PdfAConformanceException(PdfaExceptionMessageConstant.THE_INTERACTIVE_FORM_DICTIONARY_SHALL_NOT_CONTAIN_THE_XFA_KEY);
559563
}
560-
checkResources(form.getAsDictionary(PdfName.DR));
564+
checkResources(form.getAsDictionary(PdfName.DR), form);
561565

562566
PdfArray fields = form.getAsArray(PdfName.Fields);
563567
if (fields != null) {
564568
fields = getFormFields(fields);
565569
for (PdfObject field : fields) {
566570
PdfDictionary fieldDic = (PdfDictionary) field;
567-
checkResources(fieldDic.getAsDictionary(PdfName.DR));
571+
checkResources(fieldDic.getAsDictionary(PdfName.DR), fieldDic);
568572
}
569573
}
570574
}
@@ -746,7 +750,7 @@ protected void checkPageObject(PdfDictionary pageDict, PdfDictionary pageResourc
746750
PdfObject cs = pageDict.getAsDictionary(PdfName.Group).get(PdfName.CS);
747751
if (cs != null) {
748752
PdfDictionary currentColorSpaces = pageResources.getAsDictionary(PdfName.ColorSpace);
749-
checkColorSpace(PdfColorSpace.makeColorSpace(cs), currentColorSpaces, true, null);
753+
checkColorSpace(PdfColorSpace.makeColorSpace(cs), pageDict, currentColorSpaces, true, null);
750754
}
751755
}
752756
}
@@ -803,18 +807,22 @@ protected Set<PdfName> getAllowedNamedActions() {
803807
return allowedNamedActions;
804808
}
805809

810+
/**
811+
* {@inheritDoc}
812+
*/
806813
@Override
807-
protected void checkColorsUsages() {
808-
if ((rgbIsUsed || cmykIsUsed || grayIsUsed) && pdfAOutputIntentColorSpace == null) {
814+
protected void checkPageColorsUsages(PdfDictionary pageDict, PdfDictionary pageResources) {
815+
if ((rgbIsUsed || cmykIsUsed || grayIsUsed || !rgbUsedObjects.isEmpty() || !cmykUsedObjects.isEmpty() ||
816+
!grayUsedObjects.isEmpty()) && pdfAOutputIntentColorSpace == null) {
809817
throw new PdfAConformanceException(PdfaExceptionMessageConstant.IF_DEVICE_RGB_CMYK_GRAY_USED_IN_FILE_THAT_FILE_SHALL_CONTAIN_PDFA_OUTPUTINTENT_OR_DEFAULT_RGB_CMYK_GRAY_IN_USAGE_CONTEXT);
810818
}
811819

812-
if (rgbIsUsed) {
820+
if (rgbIsUsed || !rgbUsedObjects.isEmpty()) {
813821
if (!ICC_COLOR_SPACE_RGB.equals(pdfAOutputIntentColorSpace)) {
814822
throw new PdfAConformanceException(PdfaExceptionMessageConstant.DEVICERGB_MAY_BE_USED_ONLY_IF_THE_FILE_HAS_A_RGB_PDFA_OUTPUT_INTENT_OR_DEFAULTRGB_IN_USAGE_CONTEXT);
815823
}
816824
}
817-
if (cmykIsUsed) {
825+
if (cmykIsUsed || !cmykUsedObjects.isEmpty()) {
818826
if (!ICC_COLOR_SPACE_CMYK.equals(pdfAOutputIntentColorSpace)) {
819827
throw new PdfAConformanceException(PdfaExceptionMessageConstant.DEVICECMYK_MAY_BE_USED_ONLY_IF_THE_FILE_HAS_A_CMYK_PDFA_OUTPUT_INTENT_OR_DEFAULTCMYK_IN_USAGE_CONTEXT);
820828
}
@@ -826,14 +834,14 @@ protected void checkImage(PdfStream image, PdfDictionary currentColorSpaces) {
826834
PdfColorSpace colorSpace = null;
827835
if (isAlreadyChecked(image)) {
828836
colorSpace = checkedObjectsColorspace.get(image);
829-
checkColorSpace(colorSpace, currentColorSpaces, true, null);
837+
checkColorSpace(colorSpace, image, currentColorSpaces, true, null);
830838
return;
831839
}
832840

833841
PdfObject colorSpaceObj = image.get(PdfName.ColorSpace);
834842
if (colorSpaceObj != null) {
835843
colorSpace = PdfColorSpace.makeColorSpace(colorSpaceObj);
836-
checkColorSpace(colorSpace, currentColorSpaces, true, null);
844+
checkColorSpace(colorSpace, image, currentColorSpaces, true, null);
837845
checkedObjectsColorspace.put(image, colorSpace);
838846
}
839847

@@ -900,17 +908,17 @@ protected void checkImage(PdfStream image, PdfDictionary currentColorSpaces) {
900908
switch (colorSpecBox.getEnumCs()) {
901909
case 1:
902910
PdfDeviceCs.Gray deviceGrayCs = new PdfDeviceCs.Gray();
903-
checkColorSpace(deviceGrayCs, currentColorSpaces, true, null);
911+
checkColorSpace(deviceGrayCs, image, currentColorSpaces, true, null);
904912
checkedObjectsColorspace.put(image, deviceGrayCs);
905913
break;
906914
case 3:
907915
PdfDeviceCs.Rgb deviceRgbCs = new PdfDeviceCs.Rgb();
908-
checkColorSpace(deviceRgbCs, currentColorSpaces, true, null);
916+
checkColorSpace(deviceRgbCs, image, currentColorSpaces, true, null);
909917
checkedObjectsColorspace.put(image, deviceRgbCs);
910918
break;
911919
case 12:
912920
PdfDeviceCs.Cmyk deviceCmykCs = new PdfDeviceCs.Cmyk();
913-
checkColorSpace(deviceCmykCs, currentColorSpaces, true, null);
921+
checkColorSpace(deviceCmykCs, image, currentColorSpaces, true, null);
914922
checkedObjectsColorspace.put(image, deviceCmykCs);
915923
break;
916924
}
@@ -972,7 +980,7 @@ protected void checkFormXObject(PdfStream form, PdfStream contentStream) {
972980

973981
checkTransparencyGroup(form, contentStream);
974982

975-
checkResources(form.getAsDictionary(PdfName.Resources));
983+
checkResources(form.getAsDictionary(PdfName.Resources), contentStream != null ? contentStream : form);
976984
checkContentStream(form);
977985
}
978986

@@ -987,7 +995,8 @@ protected void checkTransparencyGroup(PdfStream form, PdfStream contentStream) {
987995
PdfDictionary resources = form.getAsDictionary(PdfName.Resources);
988996
if (cs != null && resources != null) {
989997
PdfDictionary currentColorSpaces = resources.getAsDictionary(PdfName.ColorSpace);
990-
checkColorSpace(PdfColorSpace.makeColorSpace(cs), currentColorSpaces, true, null);
998+
checkColorSpace(PdfColorSpace.makeColorSpace(cs), contentStream != null ? contentStream : form,
999+
currentColorSpaces, true, null);
9911000
}
9921001
}
9931002
}
@@ -1184,7 +1193,8 @@ private void fillOrderRecursively(PdfArray orderArray, Set<PdfObject> order) {
11841193
}
11851194
}
11861195

1187-
private boolean checkDefaultCS(PdfDictionary currentColorSpaces, Boolean fill, PdfName defaultCsName, int numOfComponents) {
1196+
private boolean checkDefaultCS(PdfObject pdfObject, PdfDictionary currentColorSpaces, Boolean fill, PdfName defaultCsName,
1197+
int numOfComponents) {
11881198
if (currentColorSpaces == null)
11891199
return false;
11901200
if (!currentColorSpaces.containsKey(defaultCsName))
@@ -1198,7 +1208,7 @@ private boolean checkDefaultCS(PdfDictionary currentColorSpaces, Boolean fill, P
11981208
if (defaultCs.getNumberOfComponents() != numOfComponents)
11991209
throw new PdfAConformanceException(PdfaExceptionMessageConstant.COLOR_SPACE_0_SHALL_HAVE_1_COMPONENTS).setMessageParams(defaultCsName.getValue(), numOfComponents);
12001210

1201-
checkColorSpace(defaultCs, currentColorSpaces, false, fill);
1211+
checkColorSpace(defaultCs, pdfObject, currentColorSpaces, false, fill);
12021212
return true;
12031213
}
12041214

0 commit comments

Comments
 (0)