All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.verapdf.pd.font.PDCIDFont Maven / Gradle / Ivy

There is a newer version: 1.26.1
Show newest version
/**
 * This file is part of veraPDF Parser, a module of the veraPDF project.
 * Copyright (c) 2015, veraPDF Consortium 
 * All rights reserved.
 *
 * veraPDF Parser is free software: you can redistribute it and/or modify
 * it under the terms of either:
 *
 * The GNU General public license GPLv3+.
 * You should have received a copy of the GNU General Public License
 * along with veraPDF Parser as the LICENSE.GPL file in the root of the source
 * tree.  If not, see http://www.gnu.org/licenses/ or
 * https://www.gnu.org/licenses/gpl-3.0.en.html.
 *
 * The Mozilla Public License MPLv2+.
 * You should have received a copy of the Mozilla Public License along with
 * veraPDF Parser as the LICENSE.MPL file in the root of the source tree.
 * If a copy of the MPL was not distributed with this file, you can obtain one at
 * http://mozilla.org/MPL/2.0/.
 */
package org.verapdf.pd.font;

import org.verapdf.as.ASAtom;
import org.verapdf.as.io.ASInputStream;
import org.verapdf.cos.*;
import org.verapdf.pd.font.cff.CFFFontProgram;
import org.verapdf.pd.font.cff.CFFType1FontProgram;
import org.verapdf.pd.font.cmap.CMap;
import org.verapdf.pd.font.opentype.OpenTypeFontProgram;
import org.verapdf.pd.font.truetype.CIDFontType2Program;
import org.verapdf.tools.FontProgramIDGenerator;
import org.verapdf.tools.StaticResources;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Class represents CIDFont on PD level.
 *
 * @author Sergey Shemyakov
 */
public class PDCIDFont extends PDFont {

    private static final Logger LOGGER = Logger.getLogger(PDCIDFont.class.getCanonicalName());
    private static final Double DEFAULT_CID_FONT_WIDTH = Double.valueOf(1000d);

    protected CMap cMap;
    private CIDWArray widths;
    private PDCIDSystemInfo cidSystemInfo;

    /**
     * Constructor from COSDictionary and CMap with code -> cid mapping.
     *
     * @param dictionary is COSDictionary of CIDFont.
     * @param cMap       is CMap object containing mapping code -> cid.
     */
    public PDCIDFont(COSDictionary dictionary, CMap cMap) {
        super(dictionary);
        this.cMap = cMap;
    }

    /**
     * Constructor that sets font program for this CIDFont. Can be used when
     * font program should not be parsed twice and is already read.
     *
     * @param dictionary   is COSDictionary of CIDFont.
     * @param cMap         is CMap object containing mapping code -> cid.
     * @param fontProgram  is embedded font program associated with this CIDFont.
     * @param isFontParsed is true if embedded font program has been already
     *                     parsed.
     */
    public PDCIDFont(COSDictionary dictionary, CMap cMap, FontProgram fontProgram,
                     boolean isFontParsed) {
        this(dictionary, cMap);
        this.fontProgram = fontProgram;
        this.isFontParsed = isFontParsed;
        if (fontProgram != null) {
            this.isFontParsed = true;
        }
    }

    /*
        Do not forget to set cMap!!!
     */
    protected PDCIDFont(COSDictionary dictionary) {
        super(dictionary);
    }

    /**
     * @return a stream identifying which CIDs are present in the CIDFont file.
     */
    public COSStream getCIDSet() {
        COSObject cidSet = this.fontDescriptor.getKey(ASAtom.CID_SET);
        return cidSet == null ? null : (COSStream) cidSet.getDirectBase();
    }

    /**
     * @return a specification of the mapping from CIDs to glyph indices if
     * CIDFont is a Type 2 CIDFont.
     */
    public COSObject getCIDToGIDMap() {
        return this.dictionary.getKey(ASAtom.CID_TO_GID_MAP);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Double getWidth(int code) {
        if (this.widths == null) {
            COSObject w = this.dictionary.getKey(ASAtom.W);
            if (w.empty() || w.getType() != COSObjType.COS_ARRAY) {
                return getDefaultWidth();
            }
            this.widths = new CIDWArray((COSArray) w.getDirectBase());
        }
        Double res = widths.getWidth(this.cMap.toCID(code));
        if (res == null) {
            res = getDefaultWidth();
        }
        return res;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Double getDefaultWidth() {
        COSObject dw = this.dictionary.getKey(ASAtom.DW);
        if (dw.getType().isNumber()) {
            return dw.getReal();
        } else {
            return DEFAULT_CID_FONT_WIDTH;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int readCode(InputStream stream) throws IOException {
        if (cMap != null) {
            return cMap.getCodeFromStream(stream);
        }
        throw new IOException("No CMap for Type 0 font " +
                (this.getName() == null ? "" : this.getName()));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FontProgram getFontProgram() {
        if (!this.isFontParsed) {
            this.isFontParsed = true;

            if (fontDescriptor.canParseFontFile(ASAtom.FONT_FILE2) &&
                    this.getSubtype() == ASAtom.CID_FONT_TYPE2) {
                COSStream trueTypeFontFile = fontDescriptor.getFontFile2();
                COSKey key = trueTypeFontFile.getObjectKey();
                COSObject cidToGIDMap = this.getCIDToGIDMap();
                String fontProgramID = FontProgramIDGenerator.getCIDFontType2ProgramID(key, this.cMap, cidToGIDMap);
                this.fontProgram = StaticResources.getCachedFont(fontProgramID);
                if (fontProgram == null) {
                    try (ASInputStream fontData = trueTypeFontFile.getData(COSStream.FilterFlags.DECODE)) {
                        this.fontProgram = new CIDFontType2Program(
                                fontData, this.cMap, cidToGIDMap);
                        StaticResources.cacheFontProgram(fontProgramID, this.fontProgram);
                    } catch (IOException e) {
                        LOGGER.log(Level.FINE, "Can't read TrueType font program.", e);
                    }
                }
            } else if (fontDescriptor.canParseFontFile(ASAtom.FONT_FILE3)) {
                COSStream fontFile = fontDescriptor.getFontFile3();
                COSName subtype = (COSName) fontFile.getKey(ASAtom.SUBTYPE).getDirectBase();
                COSKey key = fontFile.getObjectKey();
                try {
                    boolean isSubset = this.isSubset();
                    if (ASAtom.CID_FONT_TYPE0C == subtype.getName()) {
                        String fontProgramID = FontProgramIDGenerator.getCFFFontProgramID(key, this.cMap, isSubset);
                        this.fontProgram = StaticResources.getCachedFont(fontProgramID);
                        if (fontProgram == null) {
                            try (ASInputStream fontData = fontFile.getData(COSStream.FilterFlags.DECODE)) {
                                this.fontProgram = new CFFFontProgram(fontData, this.cMap, isSubset);
                                StaticResources.cacheFontProgram(fontProgramID, this.fontProgram);
                            }
                        }
                    } else if (ASAtom.OPEN_TYPE == subtype.getName()) {
                        ASAtom fontName = ASAtom.getASAtom(this.getName());
                        boolean isCFF = fontName != ASAtom.TRUE_TYPE && fontName != ASAtom.CID_FONT_TYPE2;
                        boolean isSymbolic = this.isSymbolic();
                        COSObject encoding = this.getEncoding();
                        String fontProgramID = FontProgramIDGenerator.getOpenTypeFontProgramID(key, isCFF, isSymbolic, encoding, this.cMap, isSubset);
                        this.fontProgram = StaticResources.getCachedFont(fontProgramID);
                        if (fontProgram == null) {
                            try (ASInputStream fontData = fontFile.getData(COSStream.FilterFlags.DECODE)) {
                                this.fontProgram = new OpenTypeFontProgram(
                                        fontData, isCFF, isSymbolic, encoding,
                                        this.cMap, isSubset);
                                StaticResources.cacheFontProgram(fontProgramID, this.fontProgram);
                            }
                        }
                    }
                } catch (IOException e) {
                    LOGGER.log(Level.FINE, "Can't read font program.", e);
                }
            } else {
                this.fontProgram = null;
            }
        }
        return this.fontProgram;
    }

    @Override
    public float getWidthFromProgram(int code) {
        int cid = this.cMap.toCID(code);
        FontProgram font = getFontProgram();
        CFFType1FontProgram cffType1 = CFFType1FontProgram.getCFFType1(font);
        if (cid != 0 && cffType1 != null) {
            // In this case we ignore internal notations of names from CFF
            // Type 1 font and use external CMap
            return cffType1.getWidthFromGID(cid);
        }
        return font.getWidth(code);
    }

    @Override
    public boolean glyphIsPresent(int code) {
        int cid = this.cMap.toCID(code);
        FontProgram font = getFontProgram();
        CFFType1FontProgram cffType1 = CFFType1FontProgram.getCFFType1(font);
        if (cid != 0 && cffType1 != null) {
            // In this case we ignore internal notations of names from CFF
            // Type 1 font and use external CMap
            return cffType1.containsGID(cid);
        }
        return font.containsCode(code);
    }

    /**
     * @return CID System Info object for this CIDFont.
     */
    public PDCIDSystemInfo getCIDSystemInfo() {
        if (this.cidSystemInfo != null) {
            return this.cidSystemInfo;
        } else {
            this.cidSystemInfo =
                    new PDCIDSystemInfo(this.dictionary.getKey(ASAtom.CID_SYSTEM_INFO));
            return this.cidSystemInfo;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy