/******************************************************************************* * Copyright 2010 Atos Worldline SAS * * Licensed by Atos Worldline SAS under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Atos Worldline SAS licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ /** * */ package net.padaf.preflight.graphics; import static net.padaf.preflight.ValidationConstants.DICTIONARY_KEY_TYPE; import static net.padaf.preflight.ValidationConstants.ERROR_GRAPHIC_INVALID_BBOX; import static net.padaf.preflight.ValidationConstants.ERROR_GRAPHIC_MISSING_FIELD; import static net.padaf.preflight.ValidationConstants.ERROR_GRAPHIC_TRANSPARENCY_GROUP; import static net.padaf.preflight.ValidationConstants.PATTERN_KEY_SHADING; import static net.padaf.preflight.ValidationConstants.XOBJECT_DICTIONARY_KEY_BBOX; import static net.padaf.preflight.ValidationConstants.XOBJECT_DICTIONARY_KEY_GROUP; import static net.padaf.preflight.ValidationConstants.XOBJECT_DICTIONARY_KEY_GROUP_S; import static net.padaf.preflight.ValidationConstants.XOBJECT_DICTIONARY_VALUE_S_TRANSPARENCY; import java.util.List; import net.padaf.preflight.DocumentHandler; import net.padaf.preflight.ValidationConstants; import net.padaf.preflight.ValidationException; import net.padaf.preflight.ValidationResult.ValidationError; import net.padaf.preflight.contentstream.ContentStreamWrapper; import net.padaf.preflight.utils.COSUtils; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; /** * This class validates XObject with the Form subtype. */ public class XObjFormValidator extends AbstractXObjValidator { /** * High level object which represents the XObjectForm */ PDXObjectForm pdXObj = null; public XObjFormValidator(DocumentHandler handler, COSStream xobj) { super(handler, xobj); this.pdXObj = new PDXObjectForm(xobj); } /* * (non-Javadoc) * * @see net.awl.edoc.pdfa.validation.graphics.AbstractXObjValidator#validate() */ @Override public List<ValidationError> validate() throws ValidationException { List<ValidationError> result = super.validate(); checkExtGraphicState(result); checkGroup(result); checkSubtype2Value(result); validateXObjectContent(result); validateShadingPattern(result); return result; } /* * (non-Javadoc) * * @seenet.awl.edoc.pdfa.validation.graphics.AbstractXObjValidator# * checkMandatoryFields(java.util.List) */ @Override protected boolean checkMandatoryFields(List<ValidationError> result) { boolean lastMod = this.xobject.getItem(COSName.getPDFName("LastModified")) != null; boolean pieceInfo = this.xobject.getItem(COSName.getPDFName("PieceInfo")) != null; // type and subtype checked before to create the Validator. if (lastMod ^ pieceInfo) { result.add(new ValidationError(ERROR_GRAPHIC_MISSING_FIELD)); return false; } COSBase bbBase = this.xobject.getItem(COSName .getPDFName(XOBJECT_DICTIONARY_KEY_BBOX)); // ---- BBox is an Array (Rectangle) if (bbBase == null || !COSUtils.isArray(bbBase, cosDocument)) { result.add(new ValidationError(ERROR_GRAPHIC_INVALID_BBOX)); return false; } return true; } /** * An Form XObject is a ContentStream. This method method uses an instance of * ContentStreamWrapper to check the Stream of this Form XObject. * * @param result * the list of error to update if the validation fails. * @return true if the validation succeed, false otherwise. * @throws ValidationException */ protected boolean validateXObjectContent(List<ValidationError> result) throws ValidationException { ContentStreamWrapper csWrapper = new ContentStreamWrapper(handler); List<ValidationError> csParseErrors = csWrapper .validXObjContentStream(pdXObj); if (csParseErrors == null || (csParseErrors != null && csParseErrors.isEmpty())) { return true; } result.addAll(csParseErrors); return false; } /** * A Form XObject may contain a Group object (Key =" Group"). If a Group * object is present, this method checks if the S entry is present and if its * value is different from "Transparency". * * @param error * the list of error to update if the validation fails. * @return true if the validation succeed, false otherwise * @throws ValidationException */ protected boolean checkGroup(List<ValidationError> error) throws ValidationException { COSBase baseGroup = this.xobject.getItem(COSName .getPDFName(XOBJECT_DICTIONARY_KEY_GROUP)); COSDictionary groupDictionary = COSUtils.getAsDictionary(baseGroup, cosDocument); if (groupDictionary != null) { if (!XOBJECT_DICTIONARY_KEY_GROUP.equals(groupDictionary .getNameAsString(DICTIONARY_KEY_TYPE))) { throw new ValidationException( "The Group dictionary hasn't Group as Type value"); } String sVal = groupDictionary .getNameAsString(XOBJECT_DICTIONARY_KEY_GROUP_S); if (sVal == null || XOBJECT_DICTIONARY_VALUE_S_TRANSPARENCY.equals(sVal)) { error.add(new ValidationError(ERROR_GRAPHIC_TRANSPARENCY_GROUP , "Group has a transparency S entry or the S entry is null.")); return false; } } return true; } /** * Check the Extended Graphic State contains in the Form XObject if it is * present. To check this ExtGState, this method uses the * net.awl.edoc.pdfa.validation.graphics.ExtGStateContainer object. * * @param errors * the list of error to update if the validation fails * @return true is the ExtGState is missing or valid, false otherwise. * @throws ValidationException */ protected boolean checkExtGraphicState(List<ValidationError> error) throws ValidationException { PDResources resources = this.pdXObj.getResources(); if (resources != null) { ExtGStateContainer extContainer = new ExtGStateContainer(resources .getCOSDictionary(), this.cosDocument); return extContainer.validateTransparencyRules(error); } return true; } /** * This method check the Shading entry of the resource dictionary if exists. * To process this validation, an instance of ShadinPattern is used. * * @param result * the list of error to update if the validation fails * @return true if the validation succeed, false otherwise. * @throws ValidationException */ protected boolean validateShadingPattern(List<ValidationError> result) throws ValidationException { PDResources resources = this.pdXObj.getResources(); boolean res = true; if (resources != null) { COSDictionary shadings = (COSDictionary) resources.getCOSDictionary() .getDictionaryObject(PATTERN_KEY_SHADING); if (shadings != null) { for (Object key : shadings.keySet()) { COSDictionary aShading = (COSDictionary) shadings .getDictionaryObject((COSName) key); ShadingPattern sp = new ShadingPattern(handler, aShading); List<ValidationError> lErrors = sp.validate(); if (lErrors != null && !lErrors.isEmpty()) { result.addAll(lErrors); res = false; } } } } return res; } /** * Check if there are no PS entry in the Form XObject dictionary * * @param errors * the list of error to update if the validation fails. * @return true if PS entry is missing, false otherwise */ protected boolean checkPS(List<ValidationError> errors) { // 6.2.4 and 6.2.5 no PS if (this.xobject.getItem(COSName.getPDFName("PS")) != null) { errors.add(new ValidationError( ValidationConstants.ERROR_GRAPHIC_UNEXPECTED_KEY, "Unexpected 'PS' Key")); return false; } return true; } /** * Check the SUbtype2 entry according to the ยง6.2.5 of the ISO 190005-1:2005 * specification. * * @param errors * the list of error to update if the validation fails. * @return true if Subtype2 is missing or different from PS, false otherwise */ protected boolean checkSubtype2Value(List<ValidationError> errors) { // 6.2.5 if Subtype2, value not PS if (this.xobject.getItem(COSName.getPDFName("Subtype2")) != null) { if ("PS".equals(this.xobject.getNameAsString(COSName .getPDFName("Subtype2")))) { errors.add(new ValidationError( ValidationConstants.ERROR_GRAPHIC_UNEXPECTED_VALUE_FOR_KEY, "Unexpected 'PS' value for 'Subtype2' Key")); return false; } } return true; } }