You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2012/07/14 21:53:50 UTC
svn commit: r1361579 [2/3] - in /pdfbox/trunk:
pdfbox/src/main/java/org/apache/pdfbox/cos/
preflight/src/main/java/org/apache/padaf/preflight/contentstream/
preflight/src/main/java/org/apache/pdfbox/preflight/
preflight/src/main/java/org/apache/pdfbox/...
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java?rev=1361579&r1=1361578&r2=1361579&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java Sat Jul 14 19:53:48 2012
@@ -21,16 +21,20 @@
package org.apache.pdfbox.preflight.font;
-
import static org.apache.pdfbox.preflight.PreflightConfiguration.RESOURCES_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_DICTIONARY_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_ENCODING;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_METRICS;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_TYPE3_DAMAGED;
import java.io.IOException;
+import java.util.List;
import java.util.Set;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.encoding.DictionaryEncoding;
@@ -40,157 +44,115 @@ import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDFontFactory;
-import org.apache.pdfbox.pdmodel.font.PDType3Font;
+import org.apache.pdfbox.preflight.PreflightConstants;
import org.apache.pdfbox.preflight.PreflightContext;
import org.apache.pdfbox.preflight.PreflightPath;
import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
import org.apache.pdfbox.preflight.content.ContentStreamException;
import org.apache.pdfbox.preflight.exception.ValidationException;
+import org.apache.pdfbox.preflight.font.container.FontContainer;
+import org.apache.pdfbox.preflight.font.container.Type3Container;
+import org.apache.pdfbox.preflight.font.util.GlyphException;
+import org.apache.pdfbox.preflight.font.util.PDFAType3StreamParser;
import org.apache.pdfbox.preflight.utils.COSUtils;
import org.apache.pdfbox.preflight.utils.ContextHelper;
-public class Type3FontValidator extends AbstractFontValidator {
- protected PDType3Font pdType3 = null;
-
- protected COSBase fontBBox = null;
- protected COSBase fontMatrix = null;
- protected COSBase charProcs = null;
- protected COSBase fontEncoding = null;
- protected COSBase firstChar = null;
- protected COSBase lastChar = null;
- protected COSBase widths = null;
- protected COSBase toUnicode = null;
- protected COSBase resources = null;
-
- protected Encoding type3Encoding = null;
-
-
- public Type3FontValidator(PreflightContext context, PDFont font)
- throws ValidationException {
- super(context, font);
- this.pdType3 = (PDType3Font) this.pFont;
+public class Type3FontValidator extends FontValidator<Type3Container> {
+ protected COSDictionary fontDictionary;
+ protected COSDocument cosDocument;
+ protected Encoding encoding;
+
+ public Type3FontValidator(PreflightContext context, PDFont font) {
+ super(context, font, new Type3Container(font));
+ this.cosDocument = context.getDocument().getDocument();
+ this.fontDictionary = (COSDictionary)font.getCOSObject();
}
- /**
- * This methods stores in attributes all required element. We extract these
- * elements because of the PDType3Font object returns sometime default value
- * if the field is missing, so to avoid mistake during required field
- * validation we store them.
- */
- private void extractFontDictionaryEntries() {
- COSDictionary fDictionary = (COSDictionary)this.pFont.getCOSObject();
- // ---- required elements
- this.fontBBox = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_FONTBBOX));
- this.fontMatrix = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_FONTMATRIX));
- this.charProcs = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_CHARPROCS));
- this.fontEncoding = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_ENCODING));
- this.firstChar = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_FIRSTCHAR));
- this.lastChar = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_LASTCHAR));
- this.widths = fDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_WIDTHS));
-
- // ---- Optional elements
- this.toUnicode = fDictionary.getItem(COSName.TO_UNICODE);
- this.resources = fDictionary.getItem(COSName.RESOURCES);
+ public void validate() throws ValidationException {
+ checkMandatoryField();
+ checkFontBBox();
+ checkFontMatrix();
+ checkEncoding();
+ checkResources();
+ checkCharProcsAndMetrics();
+ checkToUnicode();
}
- /**
- * Returns true if all required fields are present. Otherwise, this method
- * returns false and the FontContainer is updated.
- *
- * @return
- */
- private boolean checkMandatoryFields() {
- boolean all = (this.fontBBox != null);
- all = all && (this.fontMatrix != null);
- all = all && (this.charProcs != null);
- all = all && (this.fontEncoding != null);
- all = all && (this.firstChar != null);
- all = all && (this.lastChar != null);
- all = all && (this.widths != null);
- if (!all) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID));
- }
+ protected void checkMandatoryField() {
+ boolean areFieldsPResent = fontDictionary.containsKey(COSName.FONT_BBOX);
+ areFieldsPResent &= fontDictionary.containsKey(COSName.FONT_MATRIX);
+ areFieldsPResent &= fontDictionary.containsKey(COSName.CHAR_PROCS);
+ areFieldsPResent &= fontDictionary.containsKey(COSName.ENCODING);
+ areFieldsPResent &= fontDictionary.containsKey(COSName.FIRST_CHAR);
+ areFieldsPResent &= fontDictionary.containsKey(COSName.LAST_CHAR);
+ areFieldsPResent &= fontDictionary.containsKey(COSName.WIDTHS);
- /*
- * ---- Since PDF 1.5 : FontDescriptor is mandatory for Type3 font. However
- * because of the FontDescriptor is optional in PDF-1.4 no specific checks
- * are processed for PDF/A validation.
- */
- return all;
+ if (!areFieldsPResent) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "Some required fields are missing from the Font dictionary."));
+ }
}
/**
- * FontBBox and FontMatrix are required. This method checks the type and the
- * content of the FontBBox and FontMatrix element (Array of 4/6 number). If a
- * type is invalid, the FontContainer is updated and the method returns false.
- *
- * @return
+ * Check that the FontBBox element has the right format as declared in the PDF reference document.
*/
- private boolean checkFontBBoxMatrix() {
- // ---- both elements are an array
- if (!COSUtils.isArray(this.fontBBox, cosDocument)) {
- this.fontContainer
- .addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
- "The FontBBox element isn't an array"));
- return false;
- }
-
- if (!COSUtils.isArray(this.fontMatrix, cosDocument)) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "The FontMatrix element isn't an array"));
- return false;
+ private void checkFontBBox() {
+ COSBase fontBBox = fontDictionary.getItem(COSName.FONT_BBOX);
+
+ if (!COSUtils.isArray(fontBBox, cosDocument)) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The FontBBox element isn't an array"));
+ return;
}
- // ---- check the content of the FontBBox.
- // ---- Should be an array with 4 numbers
+ /*
+ * check the content of the FontBBox.
+ * Should be an array with 4 numbers
+ */
COSArray bbox = COSUtils.getAsArray(fontBBox, cosDocument);
if (bbox.size() != 4) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID, "The FontBBox element is invalid"));
- return false;
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The FontBBox element is invalid"));
+ return ;
} else {
for (int i = 0; i < 4; i++) {
COSBase elt = bbox.get(i);
if (!(COSUtils.isFloat(elt, cosDocument) || COSUtils.isInteger(elt, cosDocument))) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "An element of FontBBox isn't a number"));
- return false;
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "An element of FontBBox isn't a number"));
+ return;
}
}
}
+ }
+
+ /**
+ * Check that the FontMatrix element has the right format as declared in the PDF reference document.
+ */
+ private void checkFontMatrix() {
+ COSBase fontMatrix = fontDictionary.getItem(COSName.FONT_MATRIX);
+
+ if (!COSUtils.isArray(fontMatrix, cosDocument)) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The FontMatrix element isn't an array"));
+ return;
+ }
- // ---- check the content of the FontMatrix.
- // ---- Should be an array with 6 numbers
+ /*
+ * Check the content of the FontMatrix.
+ * Should be an array with 6 numbers
+ */
COSArray matrix = COSUtils.getAsArray(fontMatrix, cosDocument);
if (matrix.size() != 6) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID, "The FontMatrix element is invalid"));
- return false;
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The FontMatrix element is invalid"));
+ return;
} else {
for (int i = 0; i < 6; i++) {
COSBase elt = matrix.get(i);
if (!(COSUtils.isFloat(elt, cosDocument) || COSUtils.isInteger(elt, cosDocument))) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "An element of FontMatrix isn't a number"));
- return false;
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "An element of FontMatrix isn't a number"));
+ return;
}
}
}
-
- return true;
}
+ @Override
/**
* For a Type3 font, the mapping between the Character Code and the Character
* name is entirely defined in the Encoding Entry. The Encoding Entry can be a
@@ -206,71 +168,63 @@ public class Type3FontValidator extends
* a well formed "Differences" array (the array is optional)
* </UL>
*
+ * At the end of this method, if the validation succeed the Font encoding is kept in the {@link #encoding} attribute
* @return
*/
- private boolean checkEncoding() {
- EncodingManager emng = new EncodingManager();
- if (COSUtils.isString(this.fontEncoding, cosDocument)) {
- // ---- Encoding is a Name, check if it is an Existing Encoding
- String enc = COSUtils.getAsString(this.fontEncoding, cosDocument);
- try {
- type3Encoding = emng.getEncoding(COSName.getPDFName(enc));
- } catch (IOException e) {
- // ---- the encoding doesn't exist
- this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
- return false;
- }
- } else if (COSUtils.isDictionary(this.fontEncoding, cosDocument)) {
- COSDictionary encodingDictionary = COSUtils.getAsDictionary(this.fontEncoding, cosDocument);
- try {
- type3Encoding = new DictionaryEncoding(encodingDictionary);
- } catch (IOException e) {
- // ---- the encoding doesn't exist
- this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
- return false;
- }
-
- COSBase diff = encodingDictionary.getItem(COSName
- .getPDFName(FONT_DICTIONARY_KEY_DIFFERENCES));
- if (diff != null) {
- if (!COSUtils.isArray(diff, cosDocument)) {
- this.fontContainer
- .addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
- "The differences element of the encoding dictionary isn't an array"));
- return false;
- }
-
- // ---- The DictionaryEncoding object doesn't throw exception if the
- // Differences isn't well formed.
- // So check if the array has the right format.
- COSArray differences = COSUtils.getAsArray(diff, cosDocument);
- for (int i = 0; i < differences.size(); ++i) {
- COSBase item = differences.get(i);
- if (!(item instanceof COSInteger || item instanceof COSName)) {
- // ---- Error, the Differences array is invalid
- this.fontContainer
- .addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
- "Differences Array should contain COSInt or COSName, no other type"));
- return false;
- }
- }
- }
+ protected void checkEncoding() {
+ COSBase fontEncoding = fontDictionary.getItem(COSName.ENCODING);
+ if (COSUtils.isString(fontEncoding, cosDocument)) {
+ checkEncodingAsString(fontEncoding);
+ } else if (COSUtils.isDictionary(fontEncoding, cosDocument)) {
+ checkEncodingAsDictionary(fontEncoding);
} else {
- // ---- the encoding entry is invalid
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_TYPE3_DAMAGED,
- "The Encoding entry doesn't have the right type"));
- return false;
+ // the encoding entry is invalid
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,"The Encoding entry doesn't have the right type"));
}
+ }
- return true;
+ /**
+ * This method is called by the CheckEncoding method if the Encoding entry is a String.
+ * In this case, the String must be an existing encoding name. (WinAnsi, MacRoman...)
+ * @param fontEncoding
+ */
+ private void checkEncodingAsString(COSBase fontEncoding) {
+ EncodingManager emng = new EncodingManager();
+ // Encoding is a Name, check if it is an Existing Encoding
+ String enc = COSUtils.getAsString(fontEncoding, cosDocument);
+ try {
+ this.encoding = emng.getEncoding(COSName.getPDFName(enc));
+ } catch (IOException e) {
+ // the encoding doesn't exist
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_ENCODING));
+ return;
+ }
+ }
+
+ /**
+ * This method is called by the CheckEncoding method if the Encoding entry is an instance of COSDictionary.
+ * In this case, a new instance of {@link DictionaryEncoding} is created. If an IOException is thrown by the DictionaryEncoding
+ * constructor the {@link PreflightConstants.ERROR_FONTS_ENCODING} is pushed in the FontContainer.
+ *
+ * Differences entry validation is implicitly done by the DictionaryEncoding constructor.
+ * @param fontEncoding
+ */
+ private void checkEncodingAsDictionary(COSBase fontEncoding) {
+ COSDictionary encodingDictionary = COSUtils.getAsDictionary(fontEncoding, cosDocument);
+ try {
+ this.encoding = new DictionaryEncoding(encodingDictionary);
+ } catch (IOException e) {
+ // the encoding doesn't exist
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_ENCODING));
+ return;
+ }
}
/**
* CharProcs is a dictionary where the key is a character name and the value
* is a Stream which contains the glyph representation of the key.
*
- * This method checks that all character code defined in the Widths Array
+ * This method checks that all characters codes defined in the Widths Array
* exist in the CharProcs dictionary. If the CharProcs doesn't know the
* Character, it is mapped with the .notdef one.
*
@@ -280,183 +234,156 @@ public class Type3FontValidator extends
* @param errors
* @return
*/
- private boolean checkCharProcsAndMetrics() throws ValidationException {
- // ---- the Widths value can be a reference to an object
- // ---- Access the object using the COSkey
- COSArray wArr = COSUtils.getAsArray(this.widths, cosDocument);
- if (wArr == null) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "The Witdhs array is unreachable"));
- return false;
- }
-
- COSDictionary charProcsDictionary = COSUtils.getAsDictionary(this.charProcs, cosDocument);
- if (charProcsDictionary == null) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "The CharProcs element isn't a dictionary"));
- return false;
- }
-
- // ---- firstChar and lastChar must be integer.
- int fc = ((COSInteger) this.firstChar).intValue();
- int lc = ((COSInteger) this.lastChar).intValue();
-
- // ---- wArr length = (lc - fc) +1 and it is an array of int.
- // ---- If FirstChar is greater than LastChar, the validation will fail
- // because of
- // ---- the array will have an expected size <= 0.
+ private void checkCharProcsAndMetrics() throws ValidationException {
+ List<Float> widths = font.getWidths();
+ if (widths == null || widths.isEmpty()) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The Witdhs array is unreachable"));
+ return;
+ }
+
+ COSDictionary charProcs = COSUtils.getAsDictionary(fontDictionary.getItem(COSName.CHAR_PROCS), cosDocument);
+ if (charProcs == null) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The CharProcs element isn't a dictionary"));
+ return;
+ }
+
+ int fc = this.font.getFirstChar();
+ int lc = this.font.getLastChar();
+
+ /*
+ * wArr length = (lc - fc) + 1 and it is an array of int.
+ * If FirstChar is greater than LastChar, the validation will fail
+ * because of the array will have an expected size <= 0.
+ */
int expectedLength = (lc - fc) + 1;
- if (wArr.size() != expectedLength) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "The length of Witdhs array is invalid. Expected : \""
- + expectedLength + "\" Current : \"" + wArr.size() + "\""));
- return false;
+ if (widths.size() != expectedLength) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
+ "The length of Witdhs array is invalid. Expected : \"" + expectedLength + "\" Current : \"" + widths.size() + "\""));
+ return;
}
- // ---- Check width consistency
+ // Check width consistency
+ PDResources pResources = getPDResources();
for (int i = 0; i < expectedLength; i++) {
int cid = fc + i;
- COSBase arrContent = wArr.get(i);
- if (COSUtils.isNumeric(arrContent, cosDocument)) {
- float width = COSUtils.getAsFloat(arrContent, cosDocument);
-
- String charName = null;
+ float width = widths.get(i);
+
+ COSStream charStream = getCharacterStreamDescription(cid, charProcs);
+
+ if (charStream != null) {
try {
- charName = this.type3Encoding.getName(cid);
- } catch (IOException e) {
- // shouldn't occur
- throw new ValidationException("Unable to check Widths consistency", e);
- }
-
- COSBase item = charProcsDictionary.getItem(COSName.getPDFName(charName));
- COSStream charStream = COSUtils.getAsStream(item, cosDocument);
- if (charStream == null) {
- /* There are no character description, we declare the Glyph as Invalid.
- * If the character is used in a Stream, the GlyphDetail will throw an exception.
- */
- GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid,
- "The CharProcs \"" + charName
- + "\" doesn't exist, the width defines in the Font Dictionary is " + width);
- GlyphDetail glyphDetail = new GlyphDetail(cid, glyphEx);
- this.fontContainer.addKnownCidElement(glyphDetail);
- } else {
- try {
- PreflightPath vPath = context.getValidationPath();
- // --- Parse the Glyph description to obtain the Width
- PDFAType3StreamParser parser = new PDFAType3StreamParser(context, vPath.getClosestPathElement(PDPage.class)); // TODO pass the page or the Font???
- PDResources pRes = null;
- if (this.resources != null) {
- COSDictionary resAsDict = COSUtils.getAsDictionary(this.resources, cosDocument);
- if (resAsDict != null) {
- pRes = new PDResources(resAsDict);
- }
- }
- parser.resetEngine();
- parser.processSubStream(null, pRes, charStream);
-
- if (width != parser.getWidth()) {
- GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid,
- "The CharProcs \"" + charName
- + "\" should have a width equals to " + width);
- GlyphDetail glyphDetail = new GlyphDetail(cid, glyphEx);
- this.fontContainer.addKnownCidElement(glyphDetail);
- } else {
- // Glyph is OK, we keep the CID.
- GlyphDetail glyphDetail = new GlyphDetail(cid);
- this.fontContainer.addKnownCidElement(glyphDetail);
- }
- } catch (ContentStreamException e) {
- // TODO spaces/isartor-6-2-3-3-t02-fail-h.pdf --> si ajout de l'erreur dans le container le test echoue... pourquoi si la font est utilisée ca devrait planter???
- this.context.addValidationError(new ValidationError(
- ((ContentStreamException)e).getErrorCode(),
- e.getMessage()));
- return false;
- } catch (IOException e) {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_TYPE3_DAMAGED,
- "The CharProcs references an element which can't be read"));
- return false;
+
+ float fontProgamWidth = getWidthFromCharacterStream(pResources, charStream);
+ if (width == fontProgamWidth) {
+ // Glyph is OK, we keep the CID.
+ this.fontContainer.markCIDAsValid(cid);
+ } else {
+ GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid,
+ "The character with CID\"" + cid + "\" should have a width equals to " + width);
+ this.fontContainer.markCIDAsInvalid(cid, glyphEx);
}
+ } catch (ContentStreamException e) {
+ // TODO spaces/isartor-6-2-3-3-t02-fail-h.pdf --> si ajout de l'erreur dans le container le test echoue... pourquoi si la font est utilisée ca devrait planter???
+ this.context.addValidationError(new ValidationError(((ContentStreamException)e).getErrorCode(), e.getMessage()));
+ return;
+ } catch (IOException e) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED, "The CharProcs references an element which can't be read"));
+ return;
}
-
- } else {
- this.fontContainer.addError(new ValidationError(
- ERROR_FONTS_DICTIONARY_INVALID,
- "The Witdhs array is invalid. (some element aren't integer)"));
- return false;
}
}
- return true;
}
+ private PDResources getPDResources() {
+ COSBase res = this.fontDictionary.getItem(COSName.RESOURCES);
+ PDResources pResources = null;
+ COSDictionary resAsDict = COSUtils.getAsDictionary(res, cosDocument);
+ if (resAsDict != null) {
+ pResources = new PDResources(resAsDict);
+ }
+ return pResources;
+ }
+
+
+ private COSStream getCharacterStreamDescription(int cid, COSDictionary charProcs) throws ValidationException {
+ String charName = getCharNameFromEncoding(cid);
+ COSBase item = charProcs.getItem(COSName.getPDFName(charName));
+ COSStream charStream = COSUtils.getAsStream(item, cosDocument);
+ if (charStream == null) {
+ /*
+ * There are no character description, we declare the Glyph as Invalid.
+ * If the character is used in a Stream, the GlyphDetail will throw an exception.
+ */
+ GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid, "The CharProcs \"" + charName + "\" doesn't exist");
+ this.fontContainer.markCIDAsInvalid(cid, glyphEx);
+ }
+ return charStream;
+ }
+
+ private String getCharNameFromEncoding(int cid) throws ValidationException {
+ try {
+ return this.encoding.getName(cid);
+ } catch (IOException e) {
+ // shouldn't occur
+ throw new ValidationException("Unable to check Widths consistency", e);
+ }
+ }
+
+ /**
+ * Parse the Glyph description to obtain the Width
+ * @return the width of the character
+ */
+ private float getWidthFromCharacterStream(PDResources resources, COSStream charStream) throws IOException {
+ PreflightPath vPath = context.getValidationPath();
+ PDFAType3StreamParser parser = new PDFAType3StreamParser(context, vPath.getClosestPathElement(PDPage.class));
+ parser.resetEngine();
+ parser.processSubStream(null, resources, charStream);
+ return parser.getWidth();
+ }
+
/**
* If the Resources entry is present, this method check its content. Only
- * fonts and Images are checked because this resource describes glyphs. REMARK
- * : The font and the image aren't validated because they will be validated by
- * an other ValidationHelper.
+ * fonts and Images are checked because this resource describes glyphs.
*
* @return
*/
- private boolean checkResources() throws ValidationException {
- if (this.resources == null) {
- // ---- No resources dictionary.
- return true;
- }
-
- COSDictionary dictionary = COSUtils.getAsDictionary(this.resources, cosDocument);
- if (dictionary == null) {
- this.fontContainer.addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
- "The Resources element isn't a dictionary"));
- return false;
- }
-
-
- ContextHelper.validateElement(context, new PDResources(dictionary), RESOURCES_PROCESS);
- COSBase cbFont = dictionary.getItem(COSName.getPDFName(DICTIONARY_KEY_FONT));
+ private void checkResources() throws ValidationException {
+ COSBase resources = this.fontDictionary.getItem(COSName.RESOURCES);
+ if (resources != null) {
+
+ COSDictionary dictionary = COSUtils.getAsDictionary(resources, cosDocument);
+ if (dictionary == null) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The Resources element isn't a dictionary"));
+ return;
+ }
- if (cbFont != null) {
- // ---- the referenced object must be present in the PDF file
- COSDictionary dicFonts = COSUtils.getAsDictionary(cbFont, cosDocument);
- Set<COSName> keyList = dicFonts.keySet();
- for (Object key : keyList) {
+ // process Fonts and XObjects
+ ContextHelper.validateElement(context, new PDResources(dictionary), RESOURCES_PROCESS);
+ COSBase cbFont = dictionary.getItem(COSName.FONT);
+
+ if (cbFont != null) {
+ /*
+ * Check that all referenced object are present in the PDF file
+ */
+ COSDictionary dicFonts = COSUtils.getAsDictionary(cbFont, cosDocument);
+ Set<COSName> keyList = dicFonts.keySet();
+ for (Object key : keyList) {
- COSBase item = dicFonts.getItem((COSName) key);
- COSDictionary xObjFont = COSUtils.getAsDictionary(item, cosDocument);
+ COSBase item = dicFonts.getItem((COSName) key);
+ COSDictionary xObjFont = COSUtils.getAsDictionary(item, cosDocument);
- try {
- PDFont aFont = PDFontFactory.createFont(xObjFont);
- AbstractFontContainer aContainer = this.context.getFont(aFont.getCOSObject());
- // ---- another font is used in the Type3, check if the font is valid.
- if (aContainer.isValid() != org.apache.pdfbox.preflight.font.AbstractFontContainer.State.VALID) {
- this.fontContainer
- .addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
- "The Resources dictionary of type 3 font contains invalid font"));
- return false;
+ try {
+ PDFont aFont = PDFontFactory.createFont(xObjFont);
+ FontContainer aContainer = this.context.getFontContainer(aFont.getCOSObject());
+ // another font is used in the Type3, check if the font is valid.
+ if (!aContainer.isValid()) {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED, "The Resources dictionary of type 3 font contains invalid font"));
+ }
+ } catch (IOException e) {
+ throw new ValidationException("Unable to valid the Type3 : " + e.getMessage());
}
- } catch (IOException e) {
- throw new ValidationException("Unable to valid the Type3 : "
- + e.getMessage());
}
}
}
-
- return true;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see net.awl.edoc.pdfa.validation.font.FontValidator#validate()
- */
- public void validate() throws ValidationException {
- extractFontDictionaryEntries();
- boolean isValid = checkMandatoryFields();
- isValid = isValid && checkFontBBoxMatrix();
- isValid = isValid && checkEncoding();
- isValid = isValid && checkCharProcsAndMetrics();
- isValid = isValid && checkResources();
}
}
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,90 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFFont.Mapping;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class CIDType0Container extends FontContainer {
+ protected List<CFFFont> lCFonts = new ArrayList<CFFFont>();
+
+ public CIDType0Container(PDFont font) {
+ super(font);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid) {
+ // build the font container and keep it in the Handler.
+ boolean cidFound = false;
+ for (CFFFont font : this.lCFonts) {
+ Collection<Mapping> cMapping = font.getMappings();
+ for (Mapping mapping : cMapping) {
+ /*
+ * REMARK : May be this code must be changed like the Type1FontContainer to Map the SID with the character name?
+ * Not enough PDF with this kind of Font to test the current implementation
+ */
+ if (mapping.getSID()==cid) {
+ cidFound = true;
+ }
+ }
+ }
+
+ float widthInFontProgram = 0;
+ if (cidFound || cid == 0) {
+
+ float defaultGlyphWidth = 0;
+ if (this.font.getFontDescriptor() != null) {
+ defaultGlyphWidth = this.font.getFontDescriptor().getMissingWidth();
+ }
+
+ try {
+ // Search the CID in all CFFFont in the FontProgram
+ for (CFFFont cff : this.lCFonts) {
+ widthInFontProgram = cff.getWidth(cid);
+ if (widthInFontProgram != defaultGlyphWidth) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ widthInFontProgram = -1;
+ }
+ }else {
+ /*
+ * Cid 0 is commonly used as the NotDef Glyph. this glyph can be used as Space.
+ * IN PDF/A-1 the Notdef glyph can be used as space. Not in PDF/A-2
+ */
+ widthInFontProgram = -1;
+ }
+ return widthInFontProgram;
+ }
+
+ public void setlCFonts(List<CFFFont> lCFonts) {
+ this.lCFonts = lCFonts;
+ }
+
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.font.util.CIDToGIDMap;
+
+public class CIDType2Container extends FontContainer {
+
+ protected CIDToGIDMap cidToGid = null;
+
+ protected TrueTypeFont ttf = null;
+
+ public CIDType2Container(PDFont font) {
+ super(font);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid) {
+ float foundWidth = - 1;
+ final int glyphIndex = getGlyphIndex(cid);
+
+ // if glyph exists we can check the width
+ if(this.ttf != null && this.ttf.getGlyph().getGlyphs().length > glyphIndex) {
+ /* In a Mono space font program, the length of the AdvanceWidth array must be one.
+ * According to the TrueType font specification, the Last Value of the AdvanceWidth array
+ * is apply to the subsequent glyphs. So if the GlyphId is greater than the length of the array
+ * the last entry is used.
+ */
+ int numberOfLongHorMetrics = ttf.getHorizontalHeader().getNumberOfHMetrics();
+ int unitsPerEm = ttf.getHeader().getUnitsPerEm();
+ int[] advanceGlyphWidths = ttf.getHorizontalMetrics().getAdvanceWidth();
+ float glypdWidth = advanceGlyphWidths[numberOfLongHorMetrics - 1];
+ if (glyphIndex < numberOfLongHorMetrics) {
+ glypdWidth = advanceGlyphWidths[glyphIndex];
+ }
+ foundWidth = ((glypdWidth * 1000) / unitsPerEm);
+ }
+ return foundWidth;
+ }
+
+ /**
+ * If CIDToGID map is Identity, the GID equals to the CID.
+ * Otherwise the conversion is done by the CIDToGID map
+ * @param cid
+ * @return -1 CID doesn't match with a GID
+ */
+ private int getGlyphIndex(int cid){
+ int glyphIndex = cid;
+ if (this.cidToGid != null) {
+ glyphIndex = cidToGid.getGID(cid);
+ if (glyphIndex==cidToGid.NOTDEF_GLYPH_INDEX) {
+ glyphIndex = -14;
+ }
+ }
+ return glyphIndex;
+ }
+
+ public void setCidToGid(CIDToGIDMap cidToGid) {
+ this.cidToGid = cidToGid;
+ }
+
+ public void setTtf(TrueTypeFont ttf) {
+ this.ttf = ttf;
+ }
+
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.PreflightConstants;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.util.GlyphDetail;
+import org.apache.pdfbox.preflight.font.util.GlyphException;
+
+public abstract class FontContainer {
+ /**
+ * List of validation errors that occur during the font validation.
+ * If the font is used by an object in the PDF, all these errors will be appended
+ * to the Error list of the PreflightContext.
+ */
+ protected List<ValidationError> errorBuffer = new ArrayList<ValidationError>();
+ /**
+ * Boolean used to known if the font is embedded.
+ */
+ protected boolean embeddedFont = true;
+
+ /**
+ * Link CID to an Object that contain information about the Glyph state (Valid or no)
+ */
+ protected Map<Integer, GlyphDetail> computedCid = new HashMap<Integer, GlyphDetail>();
+
+ protected boolean errorsAleadyMerged = false;
+
+ protected PDFont font;
+
+ public FontContainer(PDFont font) {
+ super();
+ this.font = font;
+ }
+
+ public void push(ValidationError error) {
+ this.errorBuffer.add(error);
+ }
+
+ public void push(List<ValidationError> errors) {
+ this.errorBuffer.addAll(errors);
+ }
+
+ public List<ValidationError> getAllErrors() {
+ return this.errorBuffer;
+ }
+
+ public boolean isValid() {
+ return (this.errorBuffer.isEmpty() && isEmbeddedFont());
+ }
+
+ public boolean errorsAleadyMerged() {
+ return errorsAleadyMerged;
+ }
+
+ public void setErrorsAleadyMerged(boolean errorsAleadyMerged) {
+ this.errorsAleadyMerged = errorsAleadyMerged;
+ }
+
+ public boolean isEmbeddedFont() {
+ return embeddedFont;
+ }
+
+ public void notEmbedded() {
+ this.embeddedFont = false;
+ }
+
+ /**
+ *
+ * @param cid
+ * @throws GlyphException
+ */
+ public void checkGlyphWith(int cid) throws GlyphException {
+ if (isAlreadyComputedCid(cid)) {
+ return;
+ }
+
+ final float expectedWidth = this.font.getFontWidth(cid);
+ final float foundWidth = getFontProgramWidth(cid);
+ checkWidthsConsistency(cid, expectedWidth, foundWidth);
+ }
+
+ /**
+ * Check if the given CID is already computed
+ *
+ * @param cid the CID to check
+ * @return true if the CID has previously been marked as valid, false otherwise
+ * @throws GlyphException if the CID has previously been marked as invalid // TODO useful ??
+ */
+ protected boolean isAlreadyComputedCid(int cid) throws GlyphException {
+ boolean already = false;
+ GlyphDetail gdetail = this.computedCid.get(cid);
+ if (gdetail != null) {
+ gdetail.throwExceptionIfNotValid();
+ already = true;
+ }
+ return already;
+ }
+
+ /**
+ * Extract the Glyph width for the given CID.
+ * @param cid
+ * @return The Glyph width in 'em' unit.
+ */
+ protected abstract float getFontProgramWidth(int cid);
+
+ /**
+ * Test if both width are consistent. At the end of this method, the CID is marked as valid or invalid.
+ *
+ * @param cid
+ * @param expectedWidth
+ * @param foundWidth the glyph width found in the font program, a negative value if the CID is missing from the font.
+ * @throws GlyphException
+ */
+ protected void checkWidthsConsistency(int cid, float expectedWidth, float foundWidth) throws GlyphException {
+ if (foundWidth < 0) {
+ GlyphException e = new GlyphException(PreflightConstants.ERROR_FONTS_GLYPH_MISSING,
+ cid,
+ "The character \"" + cid
+ + "\" in the font program \""
+ + this.font.getBaseFont()
+ + "\"is missing from the Charater Encoding.");
+ markCIDAsInvalid(cid, e);
+ throw e;
+ }
+
+ // consistent is defined to be a difference of no more than 1/1000 unit.
+ if(Math.abs(foundWidth-expectedWidth) > 1) {
+ GlyphException e = new GlyphException(PreflightConstants.ERROR_FONTS_METRICS, cid,
+ "Width of the character \"" + cid
+ + "\" in the font program \""
+ + this.font.getBaseFont()
+ + "\"is inconsistent with the width in the PDF dictionary.");
+ markCIDAsInvalid(cid, e);
+ throw e;
+ }
+ markCIDAsValid(cid);
+ }
+
+ public final void markCIDAsValid(int cid) {
+ this.computedCid.put(cid, new GlyphDetail(cid));
+ }
+
+ public final void markCIDAsInvalid(int cid, GlyphException gex) {
+ this.computedCid.put(cid, new GlyphDetail(cid, gex));
+ }
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fontbox.ttf.CMAPEncodingEntry;
+import org.apache.fontbox.ttf.CMAPTable;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class TrueTypeContainer extends FontContainer {
+
+ protected TrueTypeFont ttFont;
+
+ private CMAPEncodingEntry[] cmapEncodingEntries = null;
+
+ public TrueTypeContainer(PDFont font) {
+ super(font);
+ }
+
+ public void setTrueTypeFont(TrueTypeFont ttFont) {
+ this.ttFont = ttFont;
+ initCMapEncodingEntries(); // TODO appel sur le checkWidth
+ }
+
+ /**
+ * Initialize the {@linkplain #cmapEncodingEntries} with CMaps that belong to the TrueType
+ * Font Program.
+ *
+ * Here the selection rules :
+ * <UL>
+ * <li>For a Symbolic TrueType, the Font Program has only one CMap (Checked in
+ * the checkFontFileElement method)
+ * <li>For a Non-Symbolic TrueType, the list of CMap is reordered to provide WinAnsi CMap first
+ * (plateformId : 3 / encodingId : 1) followed by MacRoman CMap (plateformId : 1 /
+ * encodingId : 0). This CMap returns the CMap which corresponds to the
+ * Encoding value of the FontDescriptor dictionary.
+ * </UL>
+ */
+ protected void initCMapEncodingEntries() {
+ if (this.cmapEncodingEntries != null) return;
+
+ CMAPTable cmap = this.ttFont.getCMAP();
+ if (this.font.getFontDescriptor().isSymbolic()) {
+ this.cmapEncodingEntries = cmap.getCmaps();
+ } else {
+ this.cmapEncodingEntries = orderCMapEntries(cmap);
+ }
+ }
+
+ private CMAPEncodingEntry[] orderCMapEntries(CMAPTable cmap) {
+ List<CMAPEncodingEntry> res = new ArrayList<CMAPEncodingEntry>();
+ boolean firstIs31 = false;
+ for (CMAPEncodingEntry cmapEntry : cmap.getCmaps()) {
+ // WinAnsi
+ if ((cmapEntry.getPlatformId() == 3) && (cmapEntry.getPlatformEncodingId() == 1)) {
+ res.add(0,cmapEntry);
+ firstIs31 = true;
+ } else if ((cmapEntry.getPlatformId() == 1)&& (cmapEntry.getPlatformEncodingId() == 0)) {
+ // MacRoman
+ if (firstIs31) {
+ // WinAnsi is present, MacRoman is set in second position
+ res.add(1, cmapEntry);
+ } else {
+ // WinAnsi is missing, MacRoman has the priority
+ res.add(0, cmapEntry);
+ }
+ } else {
+ res.add(cmapEntry);
+ }
+ }
+ return res.toArray(new CMAPEncodingEntry[res.size()]);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid) {
+ float result = -1f;
+ if (cmapEncodingEntries != null) {
+ for (CMAPEncodingEntry entry : cmapEncodingEntries) {
+ int glyphID = extractGlyphID(cid, entry);
+ if (glyphID > 0) {
+ result = extractGlyphWidth(glyphID);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * TrueType has internal CMap that map the CID used in the PDF file with an internal character identifier.
+ * This method converts the given CID in the internal font program identifier. (0 if no match found)
+ * @param cid
+ * @param cmap
+ * @return
+ */
+ private int extractGlyphID(int cid, CMAPEncodingEntry cmap) {
+ int notFoundGlyphID = 0;
+
+ int innerFontCid = cid;
+ if (cmap.getPlatformEncodingId() == 1 && cmap.getPlatformId() == 3) {
+ try {
+ Encoding fontEncoding = this.font.getFontEncoding();
+ String character = fontEncoding.getCharacter(cid);
+ if (character == null) {
+ return notFoundGlyphID;
+ }
+
+ char[] characterArray = character.toCharArray();
+ if (characterArray.length == 1 ) {
+ innerFontCid = (int)characterArray[0];
+ } else {
+ // TODO OD-PDFA-87 A faire?
+ innerFontCid = (int)characterArray[0];
+ for (int i = 1; i < characterArray.length; ++i) {
+ if (cmap.getGlyphId((int)characterArray[i]) == 0) {
+ return notFoundGlyphID; // TODO what we have to do here ???
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ // should never happen
+ return notFoundGlyphID;
+ }
+ }
+
+ // search glyph
+ return cmap.getGlyphId(innerFontCid);
+ }
+
+ private float extractGlyphWidth(int glyphID) {
+ int unitsPerEm = this.ttFont.getHeader().getUnitsPerEm();
+ int[] glyphWidths = this.ttFont.getHorizontalMetrics().getAdvanceWidth();
+ /*
+ * In a Mono space font program, the length of the AdvanceWidth array must be one.
+ * According to the TrueType font specification, the Last Value of the AdvanceWidth array
+ * is apply to the subsequent glyphs. So if the GlyphId is greater than the length of the array
+ * the last entry is used.
+ */
+ int numberOfLongHorMetrics = this.ttFont.getHorizontalHeader().getNumberOfHMetrics();
+ float glypdWidth = glyphWidths[numberOfLongHorMetrics - 1];
+ if (glyphID < numberOfLongHorMetrics) {
+ glypdWidth = glyphWidths[glyphID];
+ }
+ return ((glypdWidth * 1000) / unitsPerEm);
+ }
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import java.util.List;
+
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+
+public class Type0Container extends FontContainer {
+
+ protected FontContainer delegateFontContainer;
+
+ public Type0Container(PDFont font) {
+ super(font);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid) {
+ float width = 0;
+ if (this.delegateFontContainer != null) {
+ width = this.delegateFontContainer.getFontProgramWidth(cid);
+ }
+ return width;
+ }
+
+ public void setDelegateFontContainer(FontContainer delegateFontContainer) {
+ this.delegateFontContainer = delegateFontContainer;
+ }
+
+ public List<ValidationError> getAllErrors() {
+ if (this.delegateFontContainer != null) {
+ this.errorBuffer.addAll(this.delegateFontContainer.getAllErrors());
+ }
+ return this.errorBuffer;
+ }
+
+ public boolean isValid() {
+ boolean result = (this.errorBuffer.isEmpty() && isEmbeddedFont());
+ if (this.delegateFontContainer != null) {
+ result &= this.delegateFontContainer.isValid();
+ }
+ return result;
+ }
+
+ public boolean isEmbeddedFont() {
+ boolean result = embeddedFont;
+ if (this.delegateFontContainer != null) {
+ result &= this.delegateFontContainer.isEmbeddedFont();
+ }
+ return result;
+ }
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFFont.Mapping;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.font.util.GlyphException;
+import org.apache.pdfbox.preflight.font.util.Type1;
+
+public class Type1Container extends FontContainer {
+ /**
+ * Represent the missingWidth value of the FontDescriptor dictionary.
+ * According to the PDF Reference, if this value is missing, the default
+ * one is 0.
+ */
+ private float defaultGlyphWidth = 0;
+
+ /**
+ * true if information come from the FontFile1 Stream,
+ * false if they come from the FontFile3
+ */
+ protected boolean isFontFile1 = true;
+
+ protected Type1 type1Font;
+ protected List<CFFFont> lCFonts;
+
+ public Type1Container(PDFont font) {
+ super(font);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid) {
+ float widthResult = -1;
+ try {
+ if (isFontFile1) {
+ if (type1Font != null) {
+ widthResult = this.type1Font.getWidthOfCID(cid);
+ }
+ } else {
+ /*
+ * Retrieves the SID with the Character Name in the encoding map
+ * Need more PDF with a Type1C subfont to valid this implementation
+ */
+ String name = this.font.getFontEncoding().getName(cid);
+ for (CFFFont cff : lCFonts) {
+ int SID = cff.getEncoding().getSID(cid);
+ for (Mapping m : cff.getMappings() ){
+ if (m.getName().equals(name)) {
+ SID = m.getSID();
+ break;
+ }
+ }
+ widthResult = cff.getWidth(SID);
+ if (widthResult != defaultGlyphWidth) {
+ break;
+ }
+ }
+ }
+ } catch (GlyphException e) {
+ widthResult = -1;
+ } catch (IOException e) {
+ widthResult = -1; // TODO validation exception
+ }
+
+ return widthResult;
+ }
+
+ public void setType1Font(Type1 type1Font) {
+ this.type1Font = type1Font;
+ }
+
+ public void setFontFile1(boolean isFontFile1) {
+ this.isFontFile1 = isFontFile1;
+ }
+
+ public void setCFFFontObjects(List<CFFFont> lCFonts) {
+ this.lCFonts = lCFonts;
+ }
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.container;
+
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+/**
+ * Because Type3 font program is an inner type of the PDF file,
+ * this font container is quite different from the other because
+ * all character/glyph are already checked.
+ */
+public class Type3Container extends FontContainer {
+
+ public Type3Container(PDFont font) {
+ super(font);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid) {
+ return 0;
+ }
+
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CID_DAMAGED;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_CIDSET;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_VALUE_TYPE0C;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_VALUE_TYPE1C;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFParser;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.FontValidator;
+import org.apache.pdfbox.preflight.font.container.CIDType0Container;
+import org.apache.pdfbox.preflight.utils.COSUtils;
+
+public class CIDType0DescriptorHelper extends FontDescriptorHelper<CIDType0Container> {
+
+ public CIDType0DescriptorHelper(PreflightContext context, PDFont font, CIDType0Container fontContainer) {
+ super(context, font, fontContainer);
+ }
+
+ @Override
+ public PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor) {
+ PDStream ff3 = fontDescriptor.getFontFile3();
+ if (ff3 != null) {
+ /*
+ * Stream validation should be done by the StreamValidateHelper.
+ * Process font specific check
+ */
+ COSStream stream = ff3.getStream();
+ if (stream == null) {
+ this.fContainer.push(new ValidationError( ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
+ this.fContainer.notEmbedded();
+ } else {
+ /*
+ * Lengthx aren't mandatory for this type of font
+ * But the Subtype is a mandatory field with specific values
+ */
+ String st = stream.getNameAsString(COSName.SUBTYPE);
+ if (!(FONT_DICTIONARY_VALUE_TYPE0C.equals(st) || FONT_DICTIONARY_VALUE_TYPE1C.equals(st))) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile3 stream doesn't have the right Subtype"));
+ }
+
+ checkCIDSet(fontDescriptor);
+ }
+ }
+ return ff3;
+ }
+
+ /**
+ * If the embedded font is a subset, the CIDSet entry is mandatory and must be
+ * a Stream. If the CIDSet entry doesn't respects conditions, the FontContainer is updated.
+ *
+ * @param pfDescriptor
+ */
+ protected void checkCIDSet(PDFontDescriptorDictionary pfDescriptor) {
+ if (FontValidator.isSubSet(pfDescriptor.getFontName())) {
+ COSDocument cosDocument = context.getDocument().getDocument();
+ COSBase cidset = pfDescriptor.getCOSDictionary().getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CIDSET));
+ if (cidset == null || !COSUtils.isStream(cidset, cosDocument)) {
+ this.fContainer.push(new ValidationResult.ValidationError(ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET,
+ "The CIDSet entry is missing for the Composite Subset"));
+ }
+ }
+ }
+
+ @Override
+ protected void processFontFile(PDFontDescriptorDictionary fontDescriptor, PDStream fontFile) {
+ /*
+ * try to load the font using the java.awt.font object.
+ * if the font is invalid, an exception will be thrown
+ */
+ try {
+ CFFParser cffParser = new CFFParser();
+ List<CFFFont> lCFonts = cffParser.parse(fontFile.getByteArray());
+ if (lCFonts == null || lCFonts.isEmpty()) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+ }
+ fContainer.setlCFonts(lCFonts);
+ } catch (IOException e) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+ }
+ }
+
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CID_DAMAGED;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_CIDSET;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.fontbox.ttf.CIDFontType2Parser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.FontValidator;
+import org.apache.pdfbox.preflight.font.container.CIDType2Container;
+import org.apache.pdfbox.preflight.utils.COSUtils;
+
+public class CIDType2DescriptorHelper extends FontDescriptorHelper<CIDType2Container> {
+
+ public CIDType2DescriptorHelper(PreflightContext context, PDFont font, CIDType2Container fontContainer) {
+ super(context, font, fontContainer);
+ }
+
+ /**
+ * If the embedded font is a subset, the CIDSet entry is mandatory and must be
+ * a Stream. If the CIDSet entry doesn't respects conditions, the FontContainer is updated.
+ *
+ * @param pfDescriptor
+ */
+ protected void checkCIDSet(PDFontDescriptorDictionary pfDescriptor) {
+ if (FontValidator.isSubSet(pfDescriptor.getFontName())) {
+ COSDocument cosDocument = context.getDocument().getDocument();
+ COSBase cidset = pfDescriptor.getCOSDictionary().getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CIDSET));
+ if (cidset == null || !COSUtils.isStream(cidset, cosDocument)) {
+ this.fContainer.push(new ValidationResult.ValidationError(ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET,
+ "The CIDSet entry is missing for the Composite Subset"));
+ }
+ }
+ }
+
+ @Override
+ public PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor) {
+ PDStream ff2 = fontDescriptor.getFontFile2();
+ if (ff2 != null) {
+ /*
+ * Stream validation should be done by the StreamValidateHelper.
+ * Process font specific check
+ */
+ COSStream stream = ff2.getStream();
+ if (stream == null) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
+ this.fContainer.notEmbedded();
+ }
+ }
+ checkCIDSet(fontDescriptor);
+ return ff2;
+ }
+
+ @Override
+ protected void processFontFile(PDFontDescriptorDictionary fontDescriptor, PDStream fontFile) {
+ /*
+ * try to load the font using the java.awt.font object.
+ * if the font is invalid, an exception will be thrown
+ */
+ TrueTypeFont ttf = null;
+ try {
+ /*
+ * According to PDF Reference, CIDFontType2 is a TrueType font.
+ * Remark : Java.awt.Font throws exception when a CIDFontType2 is
+ * parsed even if it is valid.
+ */
+ ttf = new CIDFontType2Parser(true).parseTTF(new ByteArrayInputStream(fontFile.getByteArray()));
+ this.fContainer.setTtf(ttf);
+ } catch (Exception e) {
+ /*
+ * Exceptionally, Exception is catched Here because of damaged font
+ * can throw NullPointer Exception...
+ */
+ this.fContainer.push(new ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+ }
+ }
+
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,208 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_DESCRIPTOR_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_CATEGORY_PROPERTY_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT_STREAM;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT_UNKOWN;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT_XPACKET;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_RDF_ABOUT_ATTRIBUTE_MISSING;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_UNKNOWN_VALUETYPE;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_SYNTAX_STREAM_INVALID_FILTER;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_ASCENT;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_CAPHEIGHT;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_DESCENT;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_FLAGS;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_FONTBBOX;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_FONTNAME;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_ITALICANGLE;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_STEMV;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.padaf.xmpbox.XMPMetadata;
+import org.apache.padaf.xmpbox.parser.XMPDocumentBuilder;
+import org.apache.padaf.xmpbox.parser.XmpExpectedRdfAboutAttribute;
+import org.apache.padaf.xmpbox.parser.XmpParsingException;
+import org.apache.padaf.xmpbox.parser.XmpSchemaException;
+import org.apache.padaf.xmpbox.parser.XmpUnknownValueTypeException;
+import org.apache.padaf.xmpbox.parser.XmpXpacketEndException;
+import org.apache.padaf.xmpbox.type.BadFieldValueException;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.PDMetadata;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.container.FontContainer;
+import org.apache.pdfbox.preflight.font.util.FontMetaDataValidation;
+
+public abstract class FontDescriptorHelper <T extends FontContainer> {
+
+ protected T fContainer;
+
+ protected PreflightContext context;
+ protected PDFont font;
+
+ protected PDFontDescriptorDictionary fontDescriptor;
+
+ public FontDescriptorHelper(PreflightContext context, PDFont font, T fontContainer) {
+ super();
+ this.fContainer = fontContainer;
+ this.context = context;
+ this.font = font;
+ }
+
+ public void validate() {
+ PDFontDescriptor fd = this.font.getFontDescriptor();
+ // Only a PDFontDescriptorDictionary provides a way to embedded the font program.
+ if(fd != null && fd instanceof PDFontDescriptorDictionary) {
+ fontDescriptor = (PDFontDescriptorDictionary)fd;
+
+ if (checkMandatoryFields(fontDescriptor.getCOSDictionary())) {
+ if (hasOnlyOneFontFile(fontDescriptor)) {
+ PDStream fontFile = extractFontFile(fontDescriptor);
+ if (fontFile != null) {
+ processFontFile(fontDescriptor, fontFile);
+ checkFontFileMetaData(fontDescriptor, fontFile);
+ }
+ } else {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "They are more than one FontFile"));
+ }
+ }
+ } else {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_DESCRIPTOR_INVALID, "FontDescriptor is null or is a AFM Descriptor"));
+ this.fContainer.notEmbedded();
+ }
+ }
+
+ protected boolean checkMandatoryFields(COSDictionary fDescriptor) {
+ boolean areFieldsPresent = fDescriptor.containsKey(FONT_DICTIONARY_KEY_FONTNAME);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_FLAGS);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_ITALICANGLE);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_CAPHEIGHT);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_FONTBBOX);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_ASCENT);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_DESCENT);
+ areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_STEMV);
+ areFieldsPresent &= fDescriptor.containsKey(COSName.FONT_NAME);
+ if (!areFieldsPresent) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_DESCRIPTOR_INVALID, "Some mandatory fields are missing from the FontDescriptor"));
+ }
+ return areFieldsPresent;
+ }
+
+ public abstract PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor);
+
+ /**
+ * Return true if the FontDescriptor has only one FontFile entry.
+ * @param fontDescriptor
+ * @return
+ */
+ protected boolean hasOnlyOneFontFile(PDFontDescriptorDictionary fontDescriptor) {
+ PDStream ff1 = fontDescriptor.getFontFile();
+ PDStream ff2 = fontDescriptor.getFontFile2();
+ PDStream ff3 = fontDescriptor.getFontFile3();
+ return (ff1 != null ^ ff2 != null ^ ff3 != null);
+ }
+
+ protected abstract void processFontFile(PDFontDescriptorDictionary fontDescriptor, PDStream fontFile);
+
+ /**
+ * Type0, Type1 and TrueType FontValidator call this method to check the FontFile meta data.
+ *
+ * @param fontDescriptor The FontDescriptor which contains the FontFile stream
+ * @param fontFile The font file stream to check
+ */
+ protected void checkFontFileMetaData(PDFontDescriptor fontDescriptor, PDStream fontFile) {
+ PDMetadata metadata = null;
+ try {
+ metadata = fontFile.getMetadata();
+
+ if (metadata != null) {
+ // Filters are forbidden in a XMP stream
+ if (metadata.getFilters() != null && !metadata.getFilters().isEmpty()) {
+ this.fContainer.push(new ValidationError(ERROR_SYNTAX_STREAM_INVALID_FILTER, "Filter specified in font file metadata dictionnary"));
+ return;
+ }
+
+ byte[] mdAsBytes = getMetaDataStreamAsBytes(metadata);
+
+ try {
+
+ XMPDocumentBuilder xmpBuilder = new XMPDocumentBuilder();
+ XMPMetadata xmpMeta = xmpBuilder.parse(mdAsBytes);
+
+ FontMetaDataValidation fontMDval = new FontMetaDataValidation();
+ List<ValidationError> ve = new ArrayList<ValidationError>();
+ fontMDval.analyseFontName(xmpMeta, fontDescriptor, ve);
+ fontMDval.analyseRights(xmpMeta, fontDescriptor, ve);
+ this.fContainer.push(ve);
+
+ } catch (XmpUnknownValueTypeException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_UNKNOWN_VALUETYPE, e.getMessage()));
+ } catch (XmpParsingException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT, e.getMessage()));
+ } catch (XmpSchemaException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT, e.getMessage()));
+ } catch (XmpExpectedRdfAboutAttribute e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_RDF_ABOUT_ATTRIBUTE_MISSING,e.getMessage()));
+ } catch (BadFieldValueException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_CATEGORY_PROPERTY_INVALID,e.getMessage()));
+ } catch (XmpXpacketEndException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT_XPACKET, "Unable to parse font metadata due to : " + e.getMessage()));
+ }
+ }
+ } catch (IllegalStateException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT_UNKOWN, "The Metadata entry doesn't reference a stream object"));
+ }
+ }
+
+ protected final byte[] getMetaDataStreamAsBytes(PDMetadata metadata) {
+ byte[] result = null;
+ ByteArrayOutputStream bos = null;
+ InputStream metaDataContent = null;
+ try {
+ bos = new ByteArrayOutputStream();
+ metaDataContent = metadata.createInputStream();
+ IOUtils.copyLarge(metaDataContent, bos);
+ result = bos.toByteArray();
+ } catch (IOException e) {
+ this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT_STREAM, "Unable to read font metadata due to : " + e.getMessage()));
+ } finally {
+ IOUtils.closeQuietly(metaDataContent);
+ IOUtils.closeQuietly(bos);
+ }
+ return result;
+ }
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,91 @@
+/*****************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_ENCODING;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_TRUETYPE_DAMAGED;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.container.TrueTypeContainer;
+
+public class TrueTypeDescriptorHelper extends FontDescriptorHelper<TrueTypeContainer> {
+
+ public TrueTypeDescriptorHelper(PreflightContext context, PDFont font, TrueTypeContainer fontContainer) {
+ super(context, font, fontContainer);
+ }
+
+ public PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor) {
+ PDStream fontFile = fontDescriptor.getFontFile2();
+ COSStream stream = (fontFile != null ? fontFile.getStream() : null);
+ if (stream == null) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile2 is missing"));
+ this.fContainer.notEmbedded();
+ return null;
+ }
+
+ if (stream.getInt(COSName.LENGTH1) <= 0) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile entry /Length1 is invalid"));
+ return null;
+ }
+
+ return fontFile;
+ }
+
+ protected void processFontFile(PDFontDescriptorDictionary fontDescriptor, PDStream fontFile) {
+ /*
+ * Try to load the font using the TTFParser object. If the font is
+ * invalid, an exception will be thrown. Because of it is a Embedded Font
+ * Program, some tables are required and other are optional see PDF
+ * Reference (§5.8)
+ */
+ ByteArrayInputStream bis = null;
+ try {
+
+ bis = new ByteArrayInputStream(fontFile.getByteArray());
+ TrueTypeFont ttf = new TTFParser(true).parseTTF(bis);
+
+ if (fontDescriptor.isSymbolic() && ttf.getCMAP().getCmaps().length != 1) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_ENCODING, "The Encoding should be missing for the Symbolic TTF"));
+ } else {
+ ((TrueTypeContainer)this.fContainer).setTrueTypeFont(ttf);
+ // TODO check the WIdth consistency too
+ }
+ } catch (IOException e) {
+ this.fContainer.push(new ValidationError(ERROR_FONTS_TRUETYPE_DAMAGED, "The FontFile can't be read"));
+ } finally {
+ IOUtils.closeQuietly(bis);
+ }
+ }
+}
Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java
------------------------------------------------------------------------------
svn:eol-style = native