Author: leleueri Date: Sun Dec 11 19:43:24 2011 New Revision: 1213049 URL: http://svn.apache.org/viewvc?rev=1213049&view=rev Log: Addition of ICC_Profile Name
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/ValidationConstants.java pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/helpers/CatalogValidationHelper.java Modified: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/ValidationConstants.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/ValidationConstants.java?rev=1213049&r1=1213048&r2=1213049&view=diff ============================================================================== --- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/ValidationConstants.java (original) +++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/ValidationConstants.java Sun Dec 11 19:43:24 2011 @@ -267,6 +267,7 @@ public interface ValidationConstants { static final String ICC_Characterization_Data_Registry_FOGRA43 = "FOGRA43"; static final String ICC_Characterization_Data_Registry_CGATS_TR_006 = "CGATS TR 006"; + static final String ICC_Characterization_Data_Registry_CGATS_TR006 = "CGATS TR006"; static final String ICC_Characterization_Data_Registry_FOGRA39 = "FOGRA39"; static final String ICC_Characterization_Data_Registry_JC200103 = "JC200103"; static final String ICC_Characterization_Data_Registry_FOGRA27 = "FOGRA27"; @@ -275,8 +276,11 @@ public interface ValidationConstants { static final String ICC_Characterization_Data_Registry_FOGRA46 = "FOGRA46"; static final String ICC_Characterization_Data_Registry_FOGRA41 = "FOGRA41"; static final String ICC_Characterization_Data_Registry_CGATS_TR_001 = "CGATS TR 001"; + static final String ICC_Characterization_Data_Registry_CGATS_TR001 = "CGATS TR001"; static final String ICC_Characterization_Data_Registry_CGATS_TR_003 = "CGATS TR 003"; + static final String ICC_Characterization_Data_Registry_CGATS_TR003 = "CGATS TR003"; static final String ICC_Characterization_Data_Registry_CGATS_TR_005 = "CGATS TR 005"; + static final String ICC_Characterization_Data_Registry_CGATS_TR005 = "CGATS TR005"; static final String ICC_Characterization_Data_Registry_FOGRA28 = "FOGRA28"; static final String ICC_Characterization_Data_Registry_JCW2003 = "JCW2003"; static final String ICC_Characterization_Data_Registry_EUROSB204 = "EUROSB204"; @@ -290,6 +294,7 @@ public interface ValidationConstants { static final String ICC_Characterization_Data_Registry_IFRA26 = "IFRA26"; static final String ICC_Characterization_Data_Registry_JCN2002 = "JCN2002"; static final String ICC_Characterization_Data_Registry_CGATS_TR_002 = "CGATS TR 002"; + static final String ICC_Characterization_Data_Registry_CGATS_TR002 = "CGATS TR002"; static final String ICC_Characterization_Data_Registry_FOGRA33 = "FOGRA33"; static final String ICC_Characterization_Data_Registry_FOGRA37 = "FOGRA37"; static final String ICC_Characterization_Data_Registry_FOGRA31 = "FOGRA31"; @@ -405,10 +410,6 @@ public interface ValidationConstants { */ static final String ERROR_SYNTAX_STREAM_INVALID_FILTER = "1.2.7"; /** - * The stream uses a filter which isn't defined in the PDF Reference document. - */ - static final String ERROR_SYNTAX_STREAM_UNDEFINED_FILTER = "1.2.12"; - /** * The content stream has some syntax errors */ static final String ERROR_SYNTAX_CONTENT_STREAM_INVALID = "1.2.8"; @@ -423,7 +424,11 @@ public interface ValidationConstants { /** * The content stream contains an invalid argument for the operator */ - static final String ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT = "1.2.11"; + static final String ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT = "1.2.11"; + /** + * The stream uses a filter which isn't defined in the PDF Reference document. + */ + static final String ERROR_SYNTAX_STREAM_UNDEFINED_FILTER = "1.2.12"; /** * Common error about the cross ref table */ Modified: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/helpers/CatalogValidationHelper.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/helpers/CatalogValidationHelper.java?rev=1213049&r1=1213048&r2=1213049&view=diff ============================================================================== --- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/helpers/CatalogValidationHelper.java (original) +++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/helpers/CatalogValidationHelper.java Sun Dec 11 19:43:24 2011 @@ -57,10 +57,11 @@ public class CatalogValidationHelper ext protected List<String> listICC = new ArrayList<String>(); public CatalogValidationHelper(ValidatorConfig cfg) - throws ValidationException { + throws ValidationException { super(cfg); listICC.add(ICC_Characterization_Data_Registry_FOGRA43); listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_006); + listICC.add(ICC_Characterization_Data_Registry_CGATS_TR006); listICC.add(ICC_Characterization_Data_Registry_FOGRA39); listICC.add(ICC_Characterization_Data_Registry_JC200103); listICC.add(ICC_Characterization_Data_Registry_FOGRA27); @@ -71,6 +72,9 @@ public class CatalogValidationHelper ext listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_001); listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_003); listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_005); + listICC.add(ICC_Characterization_Data_Registry_CGATS_TR001); + listICC.add(ICC_Characterization_Data_Registry_CGATS_TR003); + listICC.add(ICC_Characterization_Data_Registry_CGATS_TR005); listICC.add(ICC_Characterization_Data_Registry_FOGRA28); listICC.add(ICC_Characterization_Data_Registry_JCW2003); listICC.add(ICC_Characterization_Data_Registry_EUROSB204); @@ -84,6 +88,7 @@ public class CatalogValidationHelper ext listICC.add(ICC_Characterization_Data_Registry_IFRA26); listICC.add(ICC_Characterization_Data_Registry_JCN2002); listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_002); + listICC.add(ICC_Characterization_Data_Registry_CGATS_TR002); listICC.add(ICC_Characterization_Data_Registry_FOGRA33); listICC.add(ICC_Characterization_Data_Registry_FOGRA37); listICC.add(ICC_Characterization_Data_Registry_FOGRA31); @@ -111,7 +116,7 @@ public class CatalogValidationHelper ext for (String iccStandard : listICC) { if (iccStandard.contains(name)) { // TODO check with an equal instead of contains? return true; - } + } } return false; } @@ -123,272 +128,274 @@ public class CatalogValidationHelper ext * net.awl.edoc.pdfa.validation.helpers.AbstractValidationHelper#innerValidate * (net.awl.edoc.pdfa.validation.DocumentHandler) */ - @Override - public List<ValidationError> innerValidate(DocumentHandler handler) - throws ValidationException { - List<ValidationError> result = new ArrayList<ValidationError>(0); - PDDocument pdfbox = handler.getDocument(); - PDDocumentCatalog catalog = pdfbox.getDocumentCatalog(); - if (catalog != null) { - validateActions(handler, catalog, result); - validateLang(handler, catalog, result); - validateNames(handler, catalog, result); - validateOCProperties(handler, catalog, result); - } else { - throw new ValidationException( - "There are no Catalog entry in the Document."); - } - - // ---- Check OutputIntent to know the ICC Profile - result.addAll(validateOutputIntent(handler)); - - return result; - } - - /** - * This method validates if OpenAction entry contains forbidden action type. - * It checks too if an Additional Action is present. - * - * @param handler - * @param catalog - * @param result - * @throws ValidationException - */ - protected void validateActions(DocumentHandler handler, - PDDocumentCatalog catalog, List<ValidationError> result) - throws ValidationException { - // ---- get OpenAction and Additional Action if these entries are present - List<AbstractActionManager> lActions = this.actionFact.getActions(catalog - .getCOSDictionary(), handler.getDocument().getDocument()); - for (AbstractActionManager action : lActions) { - if (!action.valid(result)) { - return; - } - } - } - - /** - * The Lang element is optional but it is recommended. This method check the - * Syntax of the Lang if this entry is present. - * - * @param handler - * @param catalog - * @param result - * @throws ValidationException - */ - protected void validateLang(DocumentHandler handler, - PDDocumentCatalog catalog, List<ValidationError> result) - throws ValidationException { - String lang = catalog.getLanguage(); - if (lang != null && !"".equals(lang) && !lang.matches("[A-Za-z]{1,8}(-[A-Za-z]{1,8})*")) { - result.add(new ValidationError(ERROR_SYNTAX_LANG_NOT_RFC1766)); - } - } - - /** - * A Catalog shall not contain the EmbeddedFiles entry. - * - * @param handler - * @param catalog - * @param result - * @throws ValidationException - */ - protected void validateNames(DocumentHandler handler, - PDDocumentCatalog catalog, List<ValidationError> result) - throws ValidationException { - PDDocumentNameDictionary names = catalog.getNames(); - if (names != null) { - PDEmbeddedFilesNameTreeNode efs = names.getEmbeddedFiles(); - if (efs != null) { - result.add(new ValidationError( - ERROR_SYNTAX_TRAILER_CATALOG_EMBEDDEDFILES,"EmbeddedFile entry is present in the Names dictionary")); - } - } - } - - /** - * A Catalog shall not contain the OCPProperties (Optional Content Properties) - * entry. - * - * @param handler - * @param catalog - * @param result - * @throws ValidationException - */ - protected void validateOCProperties(DocumentHandler handler, - PDDocumentCatalog catalog, List<ValidationError> result) - throws ValidationException { - COSBase ocp = catalog.getCOSDictionary().getItem( - COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OPTIONAL_CONTENTS)); - if (ocp != null) { - result - .add(new ValidationError(ERROR_SYNTAX_TRAILER_CATALOG_OCPROPERTIES, "A Catalog shall not contain the OCPProperties entry.")); - } - } - - /** - * This method checks the content of each OutputIntent. The S entry must - * contain GTS_PDFA1. The DestOuputProfile must contain a valid ICC Profile - * Stream. - * - * If there are more than one OutputIntent, they have to use the same ICC - * Profile. - * - * This method returns a list of ValidationError. It is empty if no errors - * have been found. - * - * @param handler - * @return - * @throws ValidationException - */ - public List<ValidationError> validateOutputIntent(DocumentHandler handler) - throws ValidationException { - List<ValidationError> result = new ArrayList<ValidationError>(0); - PDDocument pdDocument = handler.getDocument(); - PDDocumentCatalog catalog = pdDocument.getDocumentCatalog(); - COSDocument cDoc = pdDocument.getDocument(); - - COSBase cBase = catalog.getCOSDictionary().getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS)); - COSArray outputIntents = COSUtils.getAsArray(cBase, cDoc); - - Map<COSObjectKey, Boolean> tmpDestOutputProfile = new HashMap<COSObjectKey, Boolean>(); - - for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i) { - COSDictionary dictionary = COSUtils.getAsDictionary(outputIntents.get(i), cDoc); - - if (dictionary == null) { - - result.add(new ValidationError( - ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, - "OutputIntent object is null or isn't a dictionary")); - - } else { - // ---- S entry is mandatory and must be equals to GTS_PDFA1 - String sValue = dictionary.getNameAsString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_S)); - if (!OUTPUT_INTENT_DICTIONARY_VALUE_GTS_PDFA1.equals(sValue)) { - result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_S_VALUE_INVALID, - "The S entry of the OutputIntent isn't GTS_PDFA1")); - continue; - } - - // ---- OutputConditionIdentifier is a mandatory field - String outputConditionIdentifier = dictionary - .getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_OUTPUT_CONDITION_IDENTIFIER)); - if (outputConditionIdentifier == null) {// empty string is autorized (it may be an application specific value) - result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, - "The OutputIntentCondition is missing")); - continue; - } - - // ---- If OutputConditionIdentifier is "Custom" or a non Standard ICC Characterization : - // ---- DestOutputProfile and Info are mandatory - // ---- DestOutputProfile must be a ICC Profile - - // ---- Because of PDF/A conforming file needs to specify the color characteristics, the DestOutputProfile - // ---- is checked even if the OutputConditionIdentifier isn't "Custom" - COSBase dop = dictionary.getItem(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE)); - ValidationError valer = validateICCProfile(dop, cDoc, tmpDestOutputProfile, handler); - if (valer != null) { - result.add(valer); - continue; - } - - if (!isStandardICCCharacterization(outputConditionIdentifier)) { - String info = dictionary.getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_INFO)); - if (info == null || "".equals(info)) { + @Override + public List<ValidationError> innerValidate(DocumentHandler handler) + throws ValidationException { + List<ValidationError> result = new ArrayList<ValidationError>(0); + PDDocument pdfbox = handler.getDocument(); + PDDocumentCatalog catalog = pdfbox.getDocumentCatalog(); + if (catalog != null) { + validateActions(handler, catalog, result); + validateLang(handler, catalog, result); + validateNames(handler, catalog, result); + validateOCProperties(handler, catalog, result); + } else { + throw new ValidationException( + "There are no Catalog entry in the Document."); + } + + // ---- Check OutputIntent to know the ICC Profile + result.addAll(validateOutputIntent(handler)); + + return result; + } + + /** + * This method validates if OpenAction entry contains forbidden action type. + * It checks too if an Additional Action is present. + * + * @param handler + * @param catalog + * @param result + * @throws ValidationException + */ + protected void validateActions(DocumentHandler handler, + PDDocumentCatalog catalog, List<ValidationError> result) + throws ValidationException { + // ---- get OpenAction and Additional Action if these entries are present + List<AbstractActionManager> lActions = this.actionFact.getActions(catalog + .getCOSDictionary(), handler.getDocument().getDocument()); + for (AbstractActionManager action : lActions) { + if (!action.valid(result)) { + return; + } + } + } + + /** + * The Lang element is optional but it is recommended. This method check the + * Syntax of the Lang if this entry is present. + * + * @param handler + * @param catalog + * @param result + * @throws ValidationException + */ + protected void validateLang(DocumentHandler handler, + PDDocumentCatalog catalog, List<ValidationError> result) + throws ValidationException { + String lang = catalog.getLanguage(); + if (lang != null && !"".equals(lang) && !lang.matches("[A-Za-z]{1,8}(-[A-Za-z]{1,8})*")) { + result.add(new ValidationError(ERROR_SYNTAX_LANG_NOT_RFC1766)); + } + } + + /** + * A Catalog shall not contain the EmbeddedFiles entry. + * + * @param handler + * @param catalog + * @param result + * @throws ValidationException + */ + protected void validateNames(DocumentHandler handler, + PDDocumentCatalog catalog, List<ValidationError> result) + throws ValidationException { + PDDocumentNameDictionary names = catalog.getNames(); + if (names != null) { + PDEmbeddedFilesNameTreeNode efs = names.getEmbeddedFiles(); + if (efs != null) { + result.add(new ValidationError( + ERROR_SYNTAX_TRAILER_CATALOG_EMBEDDEDFILES,"EmbeddedFile entry is present in the Names dictionary")); + } + } + } + + /** + * A Catalog shall not contain the OCPProperties (Optional Content Properties) + * entry. + * + * @param handler + * @param catalog + * @param result + * @throws ValidationException + */ + protected void validateOCProperties(DocumentHandler handler, + PDDocumentCatalog catalog, List<ValidationError> result) + throws ValidationException { + COSBase ocp = catalog.getCOSDictionary().getItem( + COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OPTIONAL_CONTENTS)); + if (ocp != null) { + result + .add(new ValidationError(ERROR_SYNTAX_TRAILER_CATALOG_OCPROPERTIES, "A Catalog shall not contain the OCPProperties entry.")); + } + } + + /** + * This method checks the content of each OutputIntent. The S entry must + * contain GTS_PDFA1. The DestOuputProfile must contain a valid ICC Profile + * Stream. + * + * If there are more than one OutputIntent, they have to use the same ICC + * Profile. + * + * This method returns a list of ValidationError. It is empty if no errors + * have been found. + * + * @param handler + * @return + * @throws ValidationException + */ + public List<ValidationError> validateOutputIntent(DocumentHandler handler) + throws ValidationException { + List<ValidationError> result = new ArrayList<ValidationError>(0); + PDDocument pdDocument = handler.getDocument(); + PDDocumentCatalog catalog = pdDocument.getDocumentCatalog(); + COSDocument cDoc = pdDocument.getDocument(); + + COSBase cBase = catalog.getCOSDictionary().getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS)); + COSArray outputIntents = COSUtils.getAsArray(cBase, cDoc); + + Map<COSObjectKey, Boolean> tmpDestOutputProfile = new HashMap<COSObjectKey, Boolean>(); + + for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i) { + COSDictionary dictionary = COSUtils.getAsDictionary(outputIntents.get(i), cDoc); + + if (dictionary == null) { + + result.add(new ValidationError( + ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, + "OutputIntent object is null or isn't a dictionary")); + + } else { + // ---- S entry is mandatory and must be equals to GTS_PDFA1 + String sValue = dictionary.getNameAsString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_S)); + if (!OUTPUT_INTENT_DICTIONARY_VALUE_GTS_PDFA1.equals(sValue)) { + result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_S_VALUE_INVALID, + "The S entry of the OutputIntent isn't GTS_PDFA1")); + continue; + } + + // ---- OutputConditionIdentifier is a mandatory field + String outputConditionIdentifier = dictionary + .getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_OUTPUT_CONDITION_IDENTIFIER)); + if (outputConditionIdentifier == null) {// empty string is autorized (it may be an application specific value) result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, - "The Info entry of a OutputIntent dictionary is missing")); - continue; - } - } - } - } - return result; - } - - /** - * This method checks the destOutputProfile which must be a valid ICCProfile. - * - * If an other ICCProfile exists in the mapDestOutputProfile, a - * ValdiationError (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE) is - * returned because of only one profile is authorized. If the ICCProfile - * already exist in the mapDestOutputProfile, the method returns null. If the - * destOutputProfile contains an invalid ICCProfile, a ValidationError - * (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID) is returned If the - * destOutputProfile is an empty stream, a - * ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY) is returned. - * - * If the destOutputFile is valid, mapDestOutputProfile is updated, the - * ICCProfile is added to the document handler and null is returned. - * - * @param destOutputProfile - * @param cDoc - * @param tmpDestOutputProfile - * @param handler - * @return - * @throws ValidationException - */ - protected ValidationError validateICCProfile(COSBase destOutputProfile, - COSDocument cDoc, Map<COSObjectKey, Boolean> mapDestOutputProfile, - DocumentHandler handler) throws ValidationException { - try { - if (destOutputProfile == null) { - return new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, - "OutputIntent object uses a NULL Object"); - } - - // ---- destOutputProfile should be an instance of COSObject because of - // this is a object reference - if (destOutputProfile instanceof COSObject) { - if (mapDestOutputProfile.containsKey(new COSObjectKey( - (COSObject) destOutputProfile))) { - // ---- the profile is already checked. continue - return null; - } else if (!mapDestOutputProfile.isEmpty()) { - // ---- A DestOutputProfile exits but it isn't the same, error - return new ValidationError( - ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE, "More than one ICCProfile is defined"); - } - // else the profile will be kept in the tmpDestOutputProfile if it is valid - } - - PDStream stream = PDStream.createFromCOS(COSUtils.getAsStream( - destOutputProfile, cDoc)); - if (stream == null) { - return new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, - "OutputIntent object uses a NULL Object"); - } - - ICC_Profile iccp = ICC_Profile.getInstance(stream.getByteArray()); - // check the ICC Profile version (6.2.2) - if (iccp.getMajorVersion() == 2) { - if (iccp.getMinorVersion() > 0x20) { - // in PDF 1.4, max version is 02h.20h (meaning V 3.5) - return new ValidationError( - ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT, "Invalid version of the ICCProfile"); - } // else OK - } else if (iccp.getMajorVersion() > 2) { - // in PDF 1.4, max version is 02h.20h (meaning V 3.5) - return new ValidationError( - ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT, "Invalid version of the ICCProfile"); - } // else seems less than 2, so correct - - if (handler.getIccProfileWrapper() == null) { - handler.setIccProfileWrapper(new ICCProfileWrapper(iccp)); - } - - // ---- keep reference to avoid multiple profile definition - mapDestOutputProfile.put(new COSObjectKey((COSObject) destOutputProfile), - true); - - } catch (IllegalArgumentException e) { - // ---- this is not a ICC_Profile - return new ValidationError( - ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID, "DestOutputProfile isn't a ICCProfile"); - } catch (IOException e) { - throw new ValidationException("Unable to parse the ICC Profile", e); - } + "The OutputIntentCondition is missing")); + continue; + } + + // ---- If OutputConditionIdentifier is "Custom" or a non Standard ICC Characterization : + // ---- DestOutputProfile and Info are mandatory + // ---- DestOutputProfile must be a ICC Profile + + // ---- Because of PDF/A conforming file needs to specify the color characteristics, the DestOutputProfile + // ---- is checked even if the OutputConditionIdentifier isn't "Custom" + COSBase dop = dictionary.getItem(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE)); + ValidationError valer = validateICCProfile(dop, cDoc, tmpDestOutputProfile, handler); + if (valer != null) { + result.add(valer); + continue; + } + + if (!isStandardICCCharacterization(outputConditionIdentifier)) { + String info = dictionary.getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_INFO)); + if (info == null || "".equals(info)) { + result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, + "The Info entry of a OutputIntent dictionary is missing")); + continue; + } + } + } + } + return result; + } - return null; - } + /** + * This method checks the destOutputProfile which must be a valid ICCProfile. + * + * If an other ICCProfile exists in the mapDestOutputProfile, a + * ValdiationError (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE) is + * returned because of only one profile is authorized. If the ICCProfile + * already exist in the mapDestOutputProfile, the method returns null. If the + * destOutputProfile contains an invalid ICCProfile, a ValidationError + * (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID) is returned If the + * destOutputProfile is an empty stream, a + * ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY) is returned. + * + * If the destOutputFile is valid, mapDestOutputProfile is updated, the + * ICCProfile is added to the document handler and null is returned. + * + * @param destOutputProfile + * @param cDoc + * @param tmpDestOutputProfile + * @param handler + * @return + * @throws ValidationException + */ + protected ValidationError validateICCProfile(COSBase destOutputProfile, + COSDocument cDoc, Map<COSObjectKey, Boolean> mapDestOutputProfile, + DocumentHandler handler) throws ValidationException { + try { + if (destOutputProfile == null) { + return new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, + "OutputIntent object uses a NULL Object"); + } + + // ---- destOutputProfile should be an instance of COSObject because of + // this is a object reference + if (destOutputProfile instanceof COSObject) { + if (mapDestOutputProfile.containsKey(new COSObjectKey( + (COSObject) destOutputProfile))) { + // ---- the profile is already checked. continue + return null; + } else if (!mapDestOutputProfile.isEmpty()) { + // ---- A DestOutputProfile exits but it isn't the same, error + return new ValidationError( + ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE, "More than one ICCProfile is defined"); + } + // else the profile will be kept in the tmpDestOutputProfile if it is valid + } + + PDStream stream = PDStream.createFromCOS(COSUtils.getAsStream( + destOutputProfile, cDoc)); + if (stream == null) { + return new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, + "OutputIntent object uses a NULL Object"); + } + + ICC_Profile iccp = ICC_Profile.getInstance(stream.getByteArray()); + // check the ICC Profile version (6.2.2) + if (iccp.getMajorVersion() == 2) { + if (iccp.getMinorVersion() > 0x20) { + // TODO on lazy mode this error should be a warning? + // in PDF 1.4, max version is 02h.20h (meaning V 3.5) + return new ValidationError( + ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT, "Invalid version of the ICCProfile"); + } // else OK + } else if (iccp.getMajorVersion() > 2) { + // TODO on lazy mode this error should be a warning? + // in PDF 1.4, max version is 02h.20h (meaning V 3.5) + return new ValidationError( + ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT, "Invalid version of the ICCProfile"); + } // else seems less than 2, so correct + + if (handler.getIccProfileWrapper() == null) { + handler.setIccProfileWrapper(new ICCProfileWrapper(iccp)); + } + + // ---- keep reference to avoid multiple profile definition + mapDestOutputProfile.put(new COSObjectKey((COSObject) destOutputProfile), + true); + + } catch (IllegalArgumentException e) { + // ---- this is not a ICC_Profile + return new ValidationError( + ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID, "DestOutputProfile isn't a ICCProfile"); + } catch (IOException e) { + throw new ValidationException("Unable to parse the ICC Profile", e); + } + + return null; + } }