You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by gb...@apache.org on 2013/03/06 17:46:37 UTC
svn commit: r1453416 [7/16] - in /pdfbox/trunk/preflight: ./
src/main/java/org/apache/pdfbox/preflight/
src/main/java/org/apache/pdfbox/preflight/action/
src/main/java/org/apache/pdfbox/preflight/annotation/
src/main/java/org/apache/pdfbox/preflight/an...
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=1453416&r1=1453415&r2=1453416&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 Wed Mar 6 16:46:35 2013
@@ -57,333 +57,413 @@ import org.apache.pdfbox.preflight.font.
import org.apache.pdfbox.preflight.utils.COSUtils;
import org.apache.pdfbox.preflight.utils.ContextHelper;
-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();
- }
-
- public void validate() throws ValidationException {
- checkMandatoryField();
- checkFontBBox();
- checkFontMatrix();
- checkEncoding();
- checkResources();
- checkCharProcsAndMetrics();
- checkToUnicode();
- }
-
- 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);
-
- if (!areFieldsPResent) {
- this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "Some required fields are missing from the Font dictionary."));
- }
- }
-
- /**
- * Check that the FontBBox element has the right format as declared in the PDF reference document.
- */
- 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
- */
- COSArray bbox = COSUtils.getAsArray(fontBBox, cosDocument);
- if (bbox.size() != 4) {
- 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.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
- */
- COSArray matrix = COSUtils.getAsArray(fontMatrix, cosDocument);
- if (matrix.size() != 6) {
- 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.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "An element of FontMatrix isn't a number"));
- return;
- }
- }
- }
- }
-
- @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
- * Name (For the 5 predefined Encoding) or a Dictionary. If it is a
- * dictionary, the "Differences" array contains the correspondence between a
- * character code and a set of character name which are different from the
- * encoding entry of the dictionary.
- *
- * This method checks that the encoding is :
- * <UL>
- * <li>An existing encoding name.
- * <li>A dictionary with an existing encoding name (the name is optional) and
- * 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
- */
- 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.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,"The Encoding entry doesn't have the right type"));
- }
- }
-
- /**
- * 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 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.
- *
- * For each character, the Glyph width must be the same as the Width value
- * declared in the Widths array.
- *
- * @param errors
- * @return
- */
- 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 (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
- PDResources pResources = getPDResources();
- for (int i = 0; i < expectedLength; i++) {
- int cid = fc + i;
- float width = widths.get(i);
-
- COSStream charStream = getCharacterStreamDescription(cid, charProcs);
-
- if (charStream != null) {
- try {
-
- 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;
- }
- }
- }
- }
-
- 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.
- *
- * @return
- */
- 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;
- }
-
- // 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);
-
- 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());
- }
- }
- }
- }
- }
+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();
+ }
+
+ public void validate() throws ValidationException
+ {
+ checkMandatoryField();
+ checkFontBBox();
+ checkFontMatrix();
+ checkEncoding();
+ checkResources();
+ checkCharProcsAndMetrics();
+ checkToUnicode();
+ }
+
+ 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);
+
+ if (!areFieldsPResent)
+ {
+ this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
+ "Some required fields are missing from the Font dictionary."));
+ }
+ }
+
+ /**
+ * Check that the FontBBox element has the right format as declared in the PDF reference document.
+ */
+ 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
+ */
+ COSArray bbox = COSUtils.getAsArray(fontBBox, cosDocument);
+ if (bbox.size() != 4)
+ {
+ 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.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
+ */
+ COSArray matrix = COSUtils.getAsArray(fontMatrix, cosDocument);
+ if (matrix.size() != 6)
+ {
+ 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.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
+ "An element of FontMatrix isn't a number"));
+ return;
+ }
+ }
+ }
+ }
+
+ @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
+ * Name (For the 5 predefined Encoding) or a Dictionary. If it is a
+ * dictionary, the "Differences" array contains the correspondence between a
+ * character code and a set of character name which are different from the
+ * encoding entry of the dictionary.
+ *
+ * This method checks that the encoding is :
+ * <UL>
+ * <li>An existing encoding name.
+ * <li>A dictionary with an existing encoding name (the name is optional) and
+ * 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
+ */
+ 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.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
+ "The Encoding entry doesn't have the right type"));
+ }
+ }
+
+ /**
+ * 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 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.
+ *
+ * For each character, the Glyph width must be the same as the Width value declared in the Widths array.
+ *
+ * @param errors
+ * @return
+ */
+ 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 (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
+ PDResources pResources = getPDResources();
+ for (int i = 0; i < expectedLength; i++)
+ {
+ int cid = fc + i;
+ float width = widths.get(i);
+
+ COSStream charStream = getCharacterStreamDescription(cid, charProcs);
+
+ if (charStream != null)
+ {
+ try
+ {
+
+ 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;
+ }
+ }
+ }
+ }
+
+ 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.
+ *
+ * @return
+ */
+ 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;
+ }
+
+ // 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);
+
+ 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());
+ }
+ }
+ }
+ }
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java Wed Mar 6 16:46:35 2013
@@ -30,65 +30,82 @@ 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;
- break;
- }
- }
- if (cidFound) {
- break;
- }
- }
-
- 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;
- }
+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;
+ break;
+ }
+ }
+ if (cidFound)
+ {
+ break;
+ }
+ }
+
+ 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;
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java Wed Mar 6 16:46:35 2013
@@ -25,63 +25,73 @@ import org.apache.fontbox.ttf.TrueTypeFo
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.preflight.font.util.CIDToGIDMap;
-public class CIDType2Container extends FontContainer {
+public class CIDType2Container extends FontContainer
+{
- protected CIDToGIDMap cidToGid = null;
+ protected CIDToGIDMap cidToGid = null;
- protected TrueTypeFont ttf = 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;
- }
+ 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;
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java Wed Mar 6 16:46:35 2013
@@ -32,141 +32,158 @@ import org.apache.pdfbox.preflight.Valid
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));
- }
+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));
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java Wed Mar 6 16:46:35 2013
@@ -31,140 +31,172 @@ import org.apache.fontbox.ttf.TrueTypeFo
import org.apache.pdfbox.encoding.Encoding;
import org.apache.pdfbox.pdmodel.font.PDFont;
-public class TrueTypeContainer extends FontContainer {
+public class TrueTypeContainer extends FontContainer
+{
- protected TrueTypeFont ttFont;
+ protected TrueTypeFont ttFont;
- private CMAPEncodingEntry[] cmapEncodingEntries = null;
+ 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);
- }
+ 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);
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java Wed Mar 6 16:46:35 2013
@@ -26,47 +26,58 @@ import java.util.List;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
-public class Type0Container extends FontContainer {
+public class Type0Container extends FontContainer
+{
- protected FontContainer delegateFontContainer;
+ 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;
- }
+ 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;
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java Wed Mar 6 16:46:35 2013
@@ -30,73 +30,90 @@ import org.apache.pdfbox.pdmodel.font.PD
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;
- }
+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;
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java Wed Mar 6 16:46:35 2013
@@ -24,19 +24,21 @@ package org.apache.pdfbox.preflight.font
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.
+ * 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 class Type3Container extends FontContainer
+{
- public Type3Container(PDFont font) {
- super(font);
- }
-
- @Override
- protected float getFontProgramWidth(int cid) {
- return 0;
- }
+ public Type3Container(PDFont font)
+ {
+ super(font);
+ }
+
+ @Override
+ protected float getFontProgramWidth(int cid)
+ {
+ return 0;
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java Wed Mar 6 16:46:35 2013
@@ -47,73 +47,89 @@ import org.apache.pdfbox.preflight.font.
import org.apache.pdfbox.preflight.font.container.CIDType0Container;
import org.apache.pdfbox.preflight.utils.COSUtils;
-public class CIDType0DescriptorHelper extends FontDescriptorHelper<CIDType0Container> {
+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 for " + fontDescriptor.getFontName()));
- 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 for " + fontDescriptor.getFontName()));
- }
-
- 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"));
- }
- }
+ 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 for "
+ + fontDescriptor.getFontName()));
+ 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 for " + fontDescriptor.getFontName()));
+ }
+
+ 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"));
+ }
+ }
}
Modified: 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=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java Wed Mar 6 16:46:35 2013
@@ -44,69 +44,78 @@ import org.apache.pdfbox.preflight.font.
import org.apache.pdfbox.preflight.font.container.CIDType2Container;
import org.apache.pdfbox.preflight.utils.COSUtils;
-public class CIDType2DescriptorHelper extends FontDescriptorHelper<CIDType2Container> {
+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 for " + fontDescriptor.getFontName()));
- 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"));
- }
- }
+ 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 for "
+ + fontDescriptor.getFontName()));
+ 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"));
+ }
+ }
}