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

org.jpedal.fonts.tt.TTGlyphs Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2016 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * TTGlyphs.java
 * ---------------
 */
package org.jpedal.fonts.tt;

import java.util.Map;
import org.jpedal.PdfDecoderInt;
import org.jpedal.fonts.FontMappings;
import org.jpedal.fonts.StandardFonts;
import org.jpedal.fonts.glyph.GlyphFactory;
import org.jpedal.fonts.glyph.MarkerGlyph;
import org.jpedal.fonts.glyph.PdfGlyph;
import org.jpedal.fonts.glyph.PdfJavaGlyphs;
import org.jpedal.fonts.objects.FontData;
import org.jpedal.fonts.tt.hinting.TTVM;
import org.jpedal.utils.LogWriter;

public class TTGlyphs extends PdfJavaGlyphs {

    protected int[] CIDToGIDMap;

    float[] FontBBox= {0f,0f,1000f,1000f};

    boolean isCorrupted;

    private CMAP currentCMAP;
    private Post currentPost;
    private Glyf currentGlyf;
    private Hmtx currentHmtx;
    private Hhea currentHhea;
    private Head currentHead;

    private FontFile2 fontTable;

    //private Head currentHead;
    //private Name currentName;
    //private Maxp currentMapx;
    private Loca currentLoca;

    private TTVM vm;

    //private Hhea currentHhea;

    private CFF currentCFF;

    //int glyphCount=0;

    //assume TT and set to OTF further down
    int type= StandardFonts.TRUETYPE;

    private int unitsPerEm;

    private boolean hasCFF;

    private boolean isCID;

    /**
     * used by  non type3 font
     */
    @Override
    public PdfGlyph getEmbeddedGlyph(final GlyphFactory factory, final String glyph, final float[][]Trm, int rawInt,
                                     final String displayValue, final float currentWidth, final String key) {

        final int id=rawInt;
        if(hasGIDtoCID && isIdentity()){
            
            rawInt=CIDToGIDMap[rawInt];
           
        }
        /* flush cache if needed*/
        if(Trm!=null && (lastTrm[0][0]!=Trm[0][0])|(lastTrm[1][0]!=Trm[1][0])|
                (lastTrm[0][1]!=Trm[0][1])|(lastTrm[1][1]!=Trm[1][1])){
            lastTrm=Trm;
            flush();
        }

        //either calculate the glyph to draw or reuse if alreasy drawn
        PdfGlyph transformedGlyph2 = getEmbeddedCachedShape(id);

        if (transformedGlyph2 == null) {

            //use CMAP to get actual glyph ID
            int idx=rawInt;
            
            
            if((!isCID || !isIdentity()) && currentCMAP!=null) {
                idx = currentCMAP.convertIndexToCharacterCode(glyph, rawInt);
            }
            
            //if no value use post to lookup
            if(idx<1){
                idx = currentPost.convertGlyphToCharacterCode(glyph);
            }
            
            //shape to draw onto
            try{
                if(hasCFF){

                    transformedGlyph2=currentCFF.getCFFGlyph(factory,glyph,Trm,idx, displayValue,currentWidth,key);

                    //set raw width to use for scaling
                    if(transformedGlyph2!=null) {
                        transformedGlyph2.setWidth(getUnscaledWidth(glyph, rawInt, false));
                    }

                }else {
                    transformedGlyph2 = getTTGlyph(idx, glyph, rawInt, displayValue, factory);
                }
            }catch(final Exception e){
                //noinspection UnusedAssignment
                transformedGlyph2=null;

                LogWriter.writeLog("Exception: " + e.getMessage());
            }

            //save so we can reuse if it occurs again in this TJ command
            setEmbeddedCachedShape(id, transformedGlyph2);
        }

        return transformedGlyph2;
    }

    /*
     * creates glyph from truetype font commands
     */
    private PdfGlyph getTTGlyph(int idx, final String glyph, final int rawInt, final String displayValue, final GlyphFactory factory) {

        if(isCorrupted) {
            idx = rawInt;
        }

        PdfGlyph currentGlyph=null;

        try{
            //final boolean debug=(rawInt==2465);
            BaseTTGlyph.debug=false;


            if(idx!=-1){
                //move the pointer to the commands
                final int p=currentGlyf.getCharString(idx);

                if(p!=-1){
                    
                    if(factory.useFX()){
                        currentGlyph=factory.getGlyph(currentGlyf, fontTable, currentHmtx, idx, (unitsPerEm / 1000f), vm,baseFontName);
                        
                    }else if (TTGlyph.useHinting) {
                            currentGlyph = new TTGlyph(currentGlyf, fontTable, currentHmtx, idx, (unitsPerEm / 1000f), vm);
                        } else {
                            currentGlyph = new TTGlyph(currentGlyf, fontTable, currentHmtx, idx, (unitsPerEm / 1000f), baseFontName);
                        }
                    
                    if(BaseTTGlyph.debug) {
                        System.out.println(">>" + p + ' ' + rawInt + ' ' + displayValue + ' ' + baseFontName);
                    }

                } else if (!factory.useFX() && (" ".equals(glyph) || " ".equals(displayValue))) {
                    //Add a marker glyph in to record the number of the space glyph
                    currentGlyph = new MarkerGlyph(0,0,0,0,baseFontName);
                    currentGlyph.setGlyphNumber(idx+1);
                }
            }

        }catch(final Exception ee){
            LogWriter.writeLog("Exception "+ee);
        }

        //if(glyph.equals("fl"))

        return currentGlyph;
    }

    @Override
    public void setEncodingToUse(final boolean hasEncoding, final int fontEncoding, final boolean isCIDFont) {

        if(currentCMAP!=null){
            if(isCorrupted) {
                currentCMAP.setEncodingToUse(hasEncoding, fontEncoding, isCIDFont);
            } else {
                currentCMAP.setEncodingToUse(hasEncoding, fontEncoding, isCIDFont);
            }
        }
    }

    @Override
    public int getConvertedGlyph(final int idx){

        if(currentCMAP==null) {
            return idx;
        } else {
            return currentCMAP.convertIndexToCharacterCode(null, idx);
        }

    }

    /**
     * Return charstrings and subrs - used by PS to OTF converter
     * @return
     */
    @Override
    public Map getCharStrings() {

        if(currentCMAP!=null){
            return currentCMAP.buildCharStringTable();
        }else{
            return currentGlyf.buildCharStringTable();
        }
    }

    /*
     * creates glyph from truetype font commands
     */
    @Override
    public float getTTWidth(final String glyph, final int rawInt, final String displayValue, final boolean TTstreamisCID) {

        //use CMAP if not CID
        int idx=rawInt;

        float width=0;

        try{
            if((!TTstreamisCID)) {
                idx = currentCMAP.convertIndexToCharacterCode(glyph, rawInt);
            }

            //if no value use post to lookup
            if(idx<1) {
                idx = currentPost.convertGlyphToCharacterCode(glyph);
            }

            //if(idx!=-1)
            width=currentHmtx.getWidth(idx);

        }catch(final Exception e){
            LogWriter.writeLog("Attempting to read width " + e);
        }

        return width;
    }

    /*
     * creates glyph from truetype font commands
     */
    private float getUnscaledWidth(final String glyph, final int rawInt, final boolean TTstreamisCID) {

        //use CMAP if not CID
        int idx=rawInt;

        float width;

        try{
            if((!TTstreamisCID)) {
                idx = currentCMAP.convertIndexToCharacterCode(glyph, rawInt);
            }

            //if no value use post to lookup
            if(idx<1) {
                idx = currentPost.convertGlyphToCharacterCode(glyph);
            }

            //if(idx!=-1)
            width=currentHmtx.getUnscaledWidth(idx);

        }catch(final Exception e){
            width=1000;
            LogWriter.writeLog("Attempting to read width " + e);
        }

        return width;
    }


    @Override
    public void setGIDtoCID(final int[] cidToGIDMap) {

        hasGIDtoCID=true;
        this.CIDToGIDMap=cidToGIDMap;

    }

    /**
     * return name of font or all fonts if TTC
     * NAME will be LOWERCASE to avoid issues of capitalisation
     * when used for lookup - if no name, will default to  null
     *
     * Mode is PdfDecoder.SUBSTITUTE_* CONSTANT. RuntimeException will be thrown on invalid value
     */
    public static String[] readFontNames(final FontData fontData, final int mode) {

        /* setup read the table locations*/
        final FontFile2 currentFontFile=new FontFile2(fontData);

        //get type
        //int fontType=currentFontFile.getType();

        final int fontCount=currentFontFile.getFontCount();

        final String[] fontNames=new String[fontCount];

        /* read tables for names*/
        for(int i=0;i fontDetails) {

        /* setup read the table locations*/
        final FontFile2 currentFontFile=new FontFile2(fontData);

        //get type
        //int fontType=currentFontFile.getType();

        final int fontCount=currentFontFile.getFontCount();

        /* read tables for names*/
        for(int i=0;i stringValues= currentName.getStrings();


            if(stringValues!=null){
                for (final Integer o : stringValues.keySet()) {
                    final Integer currentKey = o;

                    final int keyInt = currentKey;
                    if (keyInt < Name.stringNames.length) {
                        fontDetails.put(Name.stringNames[currentKey], stringValues.get(currentKey));
                    }
                }
            }
        }

        if(fontData!=null) {
            fontData.close();
        }
    }

    @Override
    public int readEmbeddedFont(final boolean TTstreamisCID, final byte[] fontDataAsArray, final FontData fontData) {

        final FontFile2 currentFontFile;

        isCID=TTstreamisCID;

        /* setup read the table locations*/
        if(fontDataAsArray!=null) {
            currentFontFile = new FontFile2(fontDataAsArray);
        } else {
            currentFontFile = new FontFile2(fontData);
        }

        //select font if TTC
        //does nothing if TT
        if(FontMappings.fontSubstitutionFontID==null){
            currentFontFile.setPointer(0);
        }else{
            final Integer fontID= FontMappings.fontSubstitutionFontID.get(fontName.toLowerCase());

            if(fontID!=null) {
                currentFontFile.setPointer(fontID);
            } else {
                currentFontFile.setPointer(0);
            }
        }

        currentHead=new Head(currentFontFile);

        currentPost=new Post(currentFontFile);

        //currentName=new Name(currentFontFile);

        final Maxp currentMaxp =new Maxp(currentFontFile);
        glyphCount= currentMaxp.getGlyphCount();
        currentLoca=new Loca(currentFontFile,glyphCount,currentHead.getIndexToLocFormat());

        isCorrupted=currentLoca.isCorrupted();

        currentGlyf=new Glyf(currentFontFile,glyphCount,currentLoca.getIndices());

        currentCFF=new CFF(currentFontFile,isCID);

        hasCFF=currentCFF.hasCFFData();
        if(hasCFF) {
            type = StandardFonts.OPENTYPE;
        }

        //currentCvt=new Cvt(currentFontFile);

        if(TTGlyph.useHinting){
            //Classes in hinting package which we will delete in lgpl
            vm=new TTVM(currentFontFile, currentMaxp);
        }

        currentHhea=new Hhea(currentFontFile);

        FontBBox=currentHead.getFontBBox();

        currentHmtx=new Hmtx(currentFontFile,glyphCount,currentHhea.getNumberOfHMetrics(),(int)FontBBox[3]);

        //not all files have CMAPs
        //if(!TTstreamisCID){
        final int startPointer=currentFontFile.selectTable(FontFile2.CMAP);

        if(startPointer!=0) {
            currentCMAP = new CMAP(currentFontFile, startPointer);
        }

        //}

        unitsPerEm=currentHead.getUnitsPerEm();

        fontTable=new FontFile2(currentGlyf.getTableData(),true);

        if(fontData!=null) {
            fontData.close();
        }

        return type;
    }

    @Override
    public float[] getFontBoundingBox() {
        return FontBBox;
    }

    @Override
    public int getType() {
        return type;
    }

    //flag if Loca broken so we need to try and Substitute
    @Override
    public boolean isCorrupted() {
        return isCorrupted;
    }

    @Override
    public void setCorrupted(final boolean corrupt) {
        isCorrupted=corrupt;
    }

    @Override
    public Table getTable(final int type){

        final Table table;
        switch(type){
            case FontFile2.LOCA:
                table=currentLoca;
                break;

            case FontFile2.CMAP:
                table=currentCMAP;
                break;

            case FontFile2.HHEA:
                table=currentHhea;
                break;

            case FontFile2.HMTX:
                table=currentHmtx;
                break;

            case FontFile2.HEAD:
                table=currentHead;
                break;

            default:
                throw new RuntimeException("table not yet added to getTable)");
        }

        return table;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy