Package org.apache.padaf.preflight.font

Source Code of org.apache.padaf.preflight.font.Type1FontValidator

/*****************************************************************************
*
* 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.padaf.preflight.font;

import java.awt.Font;
import java.awt.FontFormatException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.fontbox.cff.CFFFont;
import org.apache.fontbox.cff.CFFParser;
import org.apache.padaf.preflight.DocumentHandler;
import org.apache.padaf.preflight.ValidationException;
import org.apache.padaf.preflight.ValidationResult;
import org.apache.padaf.preflight.ValidationResult.ValidationError;
import org.apache.padaf.preflight.font.type1.Type1;
import org.apache.padaf.preflight.font.type1.Type1Parser;
import org.apache.padaf.preflight.utils.COSUtils;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.pdmodel.common.PDStream;

public class Type1FontValidator extends SimpleFontValidator {

  public Type1FontValidator(DocumentHandler handler, COSObject obj)
  throws ValidationException {
    super(handler, obj);
  }

  /*
   * (non-Javadoc)
   *
   * @seenet.awl.edoc.pdfa.validation.font.SimpleFontValidator#
   * checkSpecificMandatoryFields()
   */
  protected boolean checkSpecificMandatoryFields() {
    // ---- name is required only in a PDF-1.0.
    // ---- Currently our grammar matches only with PDF-1.[1-4]
    // ---- baseFont is required and is usually the FontName
    if (basefont == null || "".equals(basefont)) {
      this.fontContainer.addError(new ValidationError(
          ERROR_FONTS_DICTIONARY_INVALID, "BaseFont is missing"));
      return false;
    }

    boolean allPresent = (firstChar != null && lastChar != null && widths != null);
    if (!allPresent) {
      this.fontContainer.addError(new ValidationError(
          ERROR_FONTS_DICTIONARY_INVALID, "Required keys are missing"));
      return false;
    }
    // else
    // ---- Event if the Font is one of the 14 standard Fonts, those keys are
    // mandatory for a PDF/A
    return true;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * net.awl.edoc.pdfa.validation.font.SimpleFontValidator#checkEncoding(org
   * .apache.pdfbox.cos.COSDocument)
   */
  protected boolean checkEncoding(COSDocument cDoc) {
    if (COSUtils.isString(this.encoding, cDoc)) {
      String encodingName = COSUtils.getAsString(this.encoding, cDoc);
      if (!(encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_MAC)
          || encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_MAC_EXP)
          || encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_WIN)
          || encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_PDFDOC) || encodingName
          .equals(FONT_DICTIONARY_VALUE_ENCODING_STD))) {
        this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
        return false;
      }
    } else if (COSUtils.isDictionary(this.encoding, cDoc)) {
      this.pFont.getFontEncoding();
    } else if (this.encoding != null) {
      this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
      return false;
    }
    //else
    // ---- According to PDF Reference, the encoding entry is optional.
    // PDF/A specification only speaks of TrueType encoding

    return true;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * net.awl.edoc.pdfa.validation.font.SimpleFontValidator#checkFontDescriptor()
   */
  @Override
  protected boolean checkFontDescriptor() throws ValidationException {
    boolean res = checkFontDescriptorMandatoryFields();
    res = res && checkFontName();
    res = res && checkFontFileElement();
    return res;
  }

  /**
   * Check if the font name is present and if fontName equals to the baseName.
   * If the validation fails, false is returned and the FontContainer is
   * updated.
   *
   * @return
   */
  boolean checkFontName() {
    String fontName = this.pFontDesc.getFontName();
    if (fontName == null) {
      this.fontContainer
      .addError(new ValidationResult.ValidationError(ERROR_FONTS_DESCRIPTOR_INVALID,
      "The FontName in font descriptor isn't the same as the BaseFont in the Font dictionary"));
      return false;
    }

    return true;
  }

  /**
   * This methods validates the Font Stream, if the font program is damaged or
   * missing the FontContainer is updated and false is returned.
   *
   * @throws ValidationException
   */
  protected boolean checkFontFileElement() throws ValidationException {
    // ---- if the this font is a Subset, the CharSet entry must be present in
    // the FontDescriptor
    if (isSubSet(pFontDesc.getFontName())) {
      String charsetStr = pFontDesc.getCharSet();
      if (charsetStr == null || "".equals(charsetStr)) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
            ERROR_FONTS_CHARSET_MISSING_FOR_SUBSET,
        "The Charset entry is missing for the Type1 Subset"));
        return false;
      }
    }

    // ---- FontFile Validation
    PDStream ff1 = pFontDesc.getFontFile();
    PDStream ff2 = pFontDesc.getFontFile2();
    PDStream ff3 = pFontDesc.getFontFile3();
    boolean onlyOne = (ff1 != null && ff2 == null && ff3 == null)
    || (ff1 == null && ff2 != null && ff3 == null)
    || (ff1 == null && ff2 == null && ff3 != null);

    if ((ff1 == null && (ff3 == null || !"Type1C".equals(((COSDictionary)ff3.getCOSObject()).getNameAsString(COSName.SUBTYPE)))) || !onlyOne) {
      this.fontContainer.addError(new ValidationResult.ValidationError(
          ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is invalid"));
      return false;
    }

    if (ff1 != null) {
      COSStream stream = ff1.getStream();
      if (stream == null) {
        this.fontContainer.addError(new ValidationResult.ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
        this.fontContainer.setFontProgramEmbedded(false);
        return false;
      }

      boolean hasLength1 = stream.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH1)) > 0;
      boolean hasLength2 = stream.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH2)) > 0;
      boolean hasLength3 = stream.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH3)) > 0;
      if (!(hasLength1 && hasLength2 && hasLength3)) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
            ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is invalid"));
        return false;
      }

      // ---- Stream validation should be done by the StreamValidateHelper.
      // ---- Process font specific check
      // ---- try to load the font using the java.awt.font object.
      // ---- if the font is invalid, an exception will be thrown
      ByteArrayInputStream bis = null;
      try {
        bis = new ByteArrayInputStream(ff1.getByteArray());
        Font.createFont(Font.TYPE1_FONT, bis);
        return checkFontMetricsDataAndFeedFontContainer(ff1) && checkFontFileMetaData(pFontDesc, ff1);
      } catch (IOException e) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
            ERROR_FONTS_TYPE1_DAMAGED, "The FontFile can't be read"));
        return false;
      } catch (FontFormatException e) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
            ERROR_FONTS_TYPE1_DAMAGED, "The FontFile is damaged"));
        return false;
      } finally {
        if (bis != null) {
          IOUtils.closeQuietly(bis);
        }
      }
    } else {
      return checkCIDFontWidths(ff3) && checkFontFileMetaData(pFontDesc, ff3);
    }
  }

  /**
   * Type1C is a CFF font format, extract all CFFFont object from the stream
   *
   * @param fontStream
   * @return
   * @throws ValidationException
   */
  protected boolean checkCIDFontWidths(PDStream fontStream)
  throws ValidationException {
    try {
      CFFParser cffParser = new CFFParser();
      List<CFFFont> lCFonts = cffParser.parse(fontStream.getByteArray());

      if (lCFonts == null || lCFonts.isEmpty()) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
            ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
        return false;
      }

      ((Type1FontContainer)this.fontContainer).setCFFFontObjects(lCFonts);

      return true;
    } catch (IOException e) {
      this.fontContainer.addError(new ValidationResult.ValidationError(
          ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
      return false;
    }
  }
  /**
   * This method checks the metric consistency and adds the FontContainer in the
   * DocumentHandler.
   *
   * @param fontStream
   * @return
   * @throws ValidationException
   */
  protected boolean checkFontMetricsDataAndFeedFontContainer(PDStream fontStream)
  throws ValidationException {
    try {

      // ---- Parse the Type1 Font program
      ByteArrayInputStream bis = new ByteArrayInputStream(fontStream
          .getByteArray());
      COSStream streamObj = fontStream.getStream();
      int length1 = streamObj.getInt(COSName
          .getPDFName(FONT_DICTIONARY_KEY_LENGTH1));
      int length2 = streamObj.getInt(COSName
          .getPDFName(FONT_DICTIONARY_KEY_LENGTH2));

      Type1Parser parserForMetrics = Type1Parser.createParserWithEncodingObject(bis, length1, length2, pFont.getFontEncoding());
      Type1 parsedData = parserForMetrics.parse();

      ((Type1FontContainer)this.fontContainer).setFontObject(parsedData);

      return true;
    } catch (IOException e) {
      throw new ValidationException("Unable to check Type1 metrics due to : "
          + e.getMessage(), e);
    }
  }
}
TOP

Related Classes of org.apache.padaf.preflight.font.Type1FontValidator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.