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

org.jpedal.fonts.StandardFonts 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


 *
 * ---------------
 * StandardFonts.java
 * ---------------
 */
package org.jpedal.fonts;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import org.jpedal.fonts.glyph.T1Glyphs;
import org.jpedal.fonts.objects.FontData;
import org.jpedal.fonts.tt.TTGlyphs;
import org.jpedal.utils.LogWriter;

public class StandardFonts {
    
    /**holds names of every character*/
    private static Map unicode_name_mapping_table = new HashMap();
    
    /**holds lookup to map char values for decoding char into name*/
    private static String[][] unicode_char_decoding_table = new String[7][335];
    
    public static final int PDF = 6;
    
    /**flag used to identify ZAPF encoding*/
    public static final int ZAPF = 5;
    
    /**flag used to identify Symbol encoding*/
    public static final int SYMBOL = 4;
    
    /**flag used to identify MacExpert encoding*/
    public static final int MACEXPERT = 3;
    
    /**flag used to identify WIN encoding*/
    public static final int WIN = 2;
    
    /**flag used to identify STD encoding*/
    public static final int STD = 1;
    
    /**flag used to identify mac encoding*/
    public static final int MAC = 0;
    
    /**mapped onto CID0 or CID2*/
    public static final int TYPE0=1228944676;
    
    public static final int TYPE1=1228944677;
    public static final int TRUETYPE=1217103210;
    
    public static final int TYPE3=1228944679;
    public static final int CIDTYPE0=-1684566726;
    public static final int CIDTYPE2=-1684566724;
    
    public static final int OPENTYPE=6;
    
    public static final int TRUETYPE_COLLECTION=7;
    
    public static final int FONT_UNSUPPORTED=8;
    
    /**constant value for ellipsis*/
    private static final String ellipsis= String.valueOf((char) Integer.parseInt("2026", 16));
    
    /**must use windows encoding because files were edited on Windows*/
    private static final String enc = "Cp1252";
    
    /**lookup table to workout index from glyf*/
    private static Map[] glyphToChar= new HashMap[7];
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] MAC_char_encoding_table;
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] WIN_char_encoding_table;
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] STD_char_encoding_table;
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] PDF_char_encoding_table;
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] ZAPF_char_encoding_table;
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] SYMBOL_char_encoding_table;
    
    /**holds lookup to map char values for decoding NAME into encoded char*/
    private static String[] MACEXPERT_char_encoding_table;
    
    /**holds lookup to map unicode values onto their glyph name*/
    private static final Map unicodeToName = new HashMap();
    
    
    /**loader to load data from jar*/
    private static ClassLoader loader = StandardFonts.class.getClassLoader();
    
    /**list of standard fonts*/
    private static Map standardFileList=new HashMap();
    
    /**flag if standard font loaded*/
    private static Map standardFontLoaded=new HashMap();
    
    /**lookup for standard fonts which we read when object created
     * (deliberately switched back to hashtable - see case 13910)
     */
    private static Map widthTableStandard = new Hashtable();
    
    /**lookup table for java fonts*/
    protected static Map javaFontList=new HashMap();
    
    /**java font versions of fonts*/
    protected static String javaFonts[] =
    {"Courier",
        "Courier-Bold",
        "Courier",
        "Courier-Bold",
        "Arial",
        "Arial-Bold",
        "Arial",
        "Arial-Italic",
        "Symbol",
        "Times New Roman",
        "Times New Roman",
        "Times New Roman",
        "Times New Roman",
        "Wingdings" };
    
    /**names of 14 local fonts used in pdf*/
    protected static String files_names[] =
    {
        "Courier",
        "Courier-Bold",
        "Courier-BoldOblique",
        "Courier-Oblique",
        "Helvetica",
        "Helvetica-Bold",
        "Helvetica-BoldOblique",
        "Helvetica-Oblique",
        "Symbol",
        "Times-Bold",
        "Times-BoldItalic",
        "Times-Italic",
        "Times-Roman",
        "ZapfDingbats" };
    
    /**alternative names of 14 local fonts used in pdf*/
    protected static String files_names_bis[] =
    {
        "CourierNew",
        "CourierNew,Bold",
        "CourierNew,BoldItalic",
        "CourierNew,Italic",
        "Arial",
        "Arial,Bold",
        "Arial,BoldItalic",
        "Arial,Italic",
        "Symbol",
        "TimesNewRoman,Bold",
        "TimesNewRoman,BoldItalic",
        "TimesNewRoman,Italic",
        "TimesNewRoman",
        "Wingdings" };
    
    /**holds lookup values used by truetype font mapping*/
    private static HashMap adobeMap;
    
    //hold bounds (deliberately switched back to hashtable - see case 13910)
    private static Map fontBounds=new Hashtable();
    
    /**flag if standard_encoding loaded*/
    public static boolean usesGlyphlist;
    
    public static void dispose(){
        
        unicode_name_mapping_table =null;
        
        unicode_char_decoding_table =null;
        
        glyphToChar=null;
        
        MAC_char_encoding_table=null;
        
        WIN_char_encoding_table=null;
        
        STD_char_encoding_table=null;
        
        PDF_char_encoding_table=null;
        
        ZAPF_char_encoding_table=null;
        
        SYMBOL_char_encoding_table=null;
        
        MACEXPERT_char_encoding_table=null;
        
        
        loader = null;
        
        standardFileList=null;
        
        standardFontLoaded=null;
        
        widthTableStandard = null;
        
        /*names of CID fonts supplied by Adobe*/
        //CIDFonts =null;
        
        /*lookup table for java fonts*/
        javaFontList=null;
        
        /*java font versions of fonts*/
        javaFonts=null;
        
        files_names=null;
        
        files_names_bis=null;
        
        adobeMap=null;
        
        fontBounds=null;
    }
    
    //////////////////////////////////////////////////
    /*
     * create lookup array so we can quickly test if
     * we have one of the 14 fonts so we can test quickly
     */
    static{
        // loop to read widths from default fonts
        for (int i = 0; i < files_names.length; i++) {
            standardFileList.put(files_names_bis[i], i);
            standardFileList.put(files_names[i], i);
        }
        
        loadAdobeMap();
    }
    
    /**return font type based on file ending or FONT_UNSUPPORTED
     * if not recognised
     * @param name
     * @return int - defined in StandardFonts (no value is FONT_UNSUPPORTED)
     */
    public static int getFontType(final String name) {
        
        int type= FONT_UNSUPPORTED;
        
        if (name.endsWith(".ttf")) {
            type=TRUETYPE;
        } else if(name.endsWith(".otf")) {
            type=OPENTYPE;
        } else if(name.endsWith(".ttc")) {
            type=TRUETYPE_COLLECTION;
            //else if(name.endsWith(".afm"))
            //  type=TYPE1;
        } else if(name.endsWith(".pfb")) {
            type=TYPE1;
        }
        
        return type;
    }
    
    /**
     * get FontBonds set in afm file
     */
    public static float[] getFontBounds(final String fontName){
        return fontBounds.get(fontName);
    }
    
    
    public static String getUnicodeName(final String key){
        return unicode_name_mapping_table.get(key);
    }
    
    public static String getUnicodeChar(final int i, final int key){
        
        return unicode_char_decoding_table[i][key];
    }
    
    public static Float getStandardWidth(String font, final String key){
        
        font=font.toLowerCase();
        
        Float value=widthTableStandard.get(font+key);
        if(value==null){
            String altfont=font;
            final int p=altfont.indexOf(',');
            if(p!=-1){
                altfont=altfont.substring(0,p);
                value=widthTableStandard.get(altfont+key);
            }
        }
        
        return value;
    }
    
    //////////////////////////////////////////////////////////////////////////
    /**
     * create mapping tables for pdf values
     * for Zapf and Symbol (not fully implmented yet)
     */
    private static void readStandardMappingTable(
            final int key,
            final String file_name){
        String char_value, NAME, VAL, line,hexVal;
        int value;
        BufferedReader input_stream = null;
        
        glyphToChar[key]=new HashMap();
        
        
        try {
            
            
            input_stream =
                    (file_name.equals("symbol.cfg"))
                    ? new BufferedReader(
                            new InputStreamReader(
                                    loader.getResourceAsStream(
                                            "org/jpedal/res/pdf/" + file_name),
                                    enc))
                    : new BufferedReader(
                            new InputStreamReader(
                                    loader.getResourceAsStream(
                                            "org/jpedal/res/pdf/" + file_name),
                                    "UTF-16"));
            
            // trap problems
            if (input_stream == null) {
                LogWriter.writeLog("Unable to open "+ file_name+ " to read standard encoding");
            }
            
            //read in lines and place in map tables for fast lookup
            while (true) {
                line = input_stream.readLine();
                if (line == null) {
                    break;
                }
                
                //write values to table, converting from Octal
                final StringTokenizer values = new StringTokenizer(line);
                
                final int tokenCount=values.countTokens();
                
                //trap for space and lines which cause problems in Zapf
                if (tokenCount>1 && (!line.contains("space"))) {
                    
                    switch(tokenCount){
                    //ignore first as token but read as char
                        case 3:
                        char_value = values.nextToken();
                        NAME = values.nextToken();
                        VAL = values.nextToken();
                        break;
                        
                        case 4:
                        hexVal=values.nextToken();
                        
                        values.nextToken(); //ignore in this case
                        NAME = values.nextToken();
                        VAL = values.nextToken();
                        
                        char_value=Character.toString((char)Integer.parseInt(hexVal,16));
                        break;
                        
                        case 2: //zapf values
                            char_value = " ";
                            NAME = values.nextToken();
                            VAL = values.nextToken();
                        break;
                        
                        default:
                            char_value = values.nextToken();
                            NAME = values.nextToken();
                            VAL = values.nextToken();
                        
                    }
                
                    if(tokenCount!=2){ //do not add forZapf
                        unicode_name_mapping_table.put(key + NAME, char_value);
                    }
                    
                    glyphToChar[key].put(NAME, Integer.parseInt(VAL));
                    
                    //20021104 added to make sure names in list as well
                    //if (file_name.equals("zapf.cfg"))
                    if(tokenCount!=2){ //do not add forZapf
                        unicode_name_mapping_table.put(NAME, char_value);
                    }
                    
                    //convert if there is a value
                    if (Character.isDigit(VAL.charAt(0))) {
                        
                        value = Integer.parseInt(VAL, 8);
                        
                        if(key==ZAPF) {
                            ZAPF_char_encoding_table[value] = char_value;
                        } else if(key==SYMBOL) {
                            SYMBOL_char_encoding_table[value] = char_value;
                        } else if(key==MACEXPERT) {
                            MACEXPERT_char_encoding_table[value] = char_value;
                        }
                        
                        unicode_char_decoding_table[key][value]=NAME;
                        
                    }
                }
            }
        } catch (final Exception e) {
            LogWriter.writeLog("Exception " + e + " reading lookup table for pdf");
        }
        
        if(input_stream!=null){
            try{
                input_stream.close();
            }catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " reading lookup table for pdf  for abobe map");
            }
        }
    }
    //////////////////////////////////////////////
    /**
     * create mapping tables for 'standard' pdf values
     * by reading in data from files (which are tables
     * taken from Adobe's standard documentation
     */
    private static void readStandardMappingTable(final int idx) {
        
        String char_value, NAME, STD_value, MAC_value, WIN_value,PDF_value,raw;
        int mac_value, win_value, std_value;
        String line;
        BufferedReader input_stream = null;
        
        //needed for comparison table
        if(idx==MAC) {
            checkLoaded(WIN);
        }
        
        
        try {
            
            //initialise inverse lookup
            glyphToChar[idx]=new HashMap();
            
            input_stream =
                    new BufferedReader(
                            new InputStreamReader(
                                    loader.getResourceAsStream(
                                            "org/jpedal/res/pdf/standard_encoding.cfg"),enc));
            
            usesGlyphlist=true;
            
            // trap problems
            if (input_stream == null) {
                LogWriter.writeLog("Unable to open standard_encoding.cfg from jar");
            }
            
            //read in lines and place in map tables for fast lookup
            while (true) {
                line = input_stream.readLine();
                if (line == null) {
                    break;
                }
                
                //write values to table, converting from Octal
                final StringTokenizer values = new StringTokenizer(line);
                final int count=values.countTokens();
                
                //format is NAME, STD,MAC,WIN,PDF, unicode value (as hex) char from PDF reference ignored) or
                //NAME, STD,MAC,WIN,PDF,  char (used for fi,fl and other double values)
                //ignore first as token but read as char
                
                NAME = values.nextToken();
                STD_value = values.nextToken();
                MAC_value = values.nextToken();
                WIN_value = values.nextToken();
                PDF_value =values.nextToken();
                raw=values.nextToken();
                
                if(count==7) {
                    char_value=Character.toString((char)Integer.parseInt(raw,16));
                } else {
                    char_value=raw;
                }
                
                unicodeToName.put(char_value, NAME);
                
                
                //convert if possible
                if((idx==MAC) &&(Character.isDigit(MAC_value.charAt(0)))) {
                    mac_value = Integer.parseInt(MAC_value, 8);
                    
                    //substitute ellipsis
                    if(mac_value==201) {
                        char_value=ellipsis;
                    }
                    
                    MAC_char_encoding_table[mac_value] =char_value;
                    unicode_char_decoding_table[MAC][mac_value]=NAME;
                    
                    glyphToChar[MAC].put(NAME, mac_value);
                    
                    //build a comparison table to test encoding
                    //if (Character.isDigit(WIN_value.charAt(0)))
                    //	win_value = Integer.parseInt(WIN_value, 8);
                    
                }else if ((idx==STD)&&(Character.isDigit(STD_value.charAt(0)))) {
                    std_value = Integer.parseInt(STD_value, 8);
                    
                    //substitute ellipsis
                    if(std_value==188) {
                        char_value=ellipsis;
                    }
                    
                    STD_char_encoding_table[std_value] =char_value;
                    unicode_char_decoding_table[STD][std_value]=NAME;
                    
                    glyphToChar[STD].put(NAME, std_value);
                    
                }else if ((idx==PDF)&&(Character.isDigit(PDF_value.charAt(0)))) {
                    std_value = Integer.parseInt(PDF_value, 8);
                    
                    //substitute ellipsis
                    if(std_value==131) {
                        char_value=ellipsis;
                    }
                    
                    PDF_char_encoding_table[std_value] =char_value;
                    unicode_char_decoding_table[PDF][std_value]=NAME;
                    
                }else if (idx== WIN && Character.isDigit(WIN_value.charAt(0))) {
                    win_value = Integer.parseInt(WIN_value, 8);
                    
                    //substitute ellipsis
                    if(win_value==133) {
                        char_value=ellipsis;
                    }
                    
                    WIN_char_encoding_table[win_value] =char_value;
                    unicode_char_decoding_table[WIN][win_value]=NAME;
                    
                    glyphToChar[WIN].put(NAME, win_value);
                    
                    
                }
                
                //save details for later
                unicode_name_mapping_table.put(NAME, char_value);
                
                
            }
            
            //add in alternative MAC space   312 octal == space
            if(idx==MAC) {
                MAC_char_encoding_table[202]=" ";
            }
            
            //add in alternative WIN values
            if(idx== WIN){
                WIN_char_encoding_table[160]=" ";
                WIN_char_encoding_table[255]="-";
                
                unicode_char_decoding_table[WIN][160]="space";
                
            }
            
        } catch (final Exception e) {
            LogWriter.writeLog("Exception " + e + " reading lookup table for pdf  for "+idx);
        }
        
        if(input_stream!=null){
            try{
                input_stream.close();
            }catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " reading lookup table for pdf  for abobe map");
            }
        }
    }
    
    /*used internally when we needed to convert bytes to MacROman to build new tables*/
    /*private static String byteToEncodedString(String value,String enc) throws Exception{
    
     String s=null;

     //Create the encoder and decoder for ISO-8859-1
     Charset charset = Charset.forName(enc);
     CharsetDecoder decoder = charset.newDecoder();
     CharsetEncoder encoder = charset.newEncoder();

     // Convert a string to ISO-LATIN-1 bytes in a ByteBuffer
     // The new ByteBuffer is ready to be read.
     java.nio.ByteBuffer bbuf = encoder.encode(CharBuffer.wrap("a"));
     bbuf.clear();
     //java.nio.ByteBuffer bbuf=new ByteBuffer();
     bbuf.put(0,(byte) Integer.parseInt(value,16));
     // Convert ISO-LATIN-1 bytes in a ByteBuffer to a character ByteBuffer and then to a string.
     // The new ByteBuffer is ready to be read.
     CharBuffer cbuf = decoder.decode(bbuf);
     s = cbuf.toString();

     System.out.println(Integer.toHexString((int)s.charAt(0)));

     return s;
     }*/

    /**
     * Returns the appropriate glyph name for a supplied unicode value.
     * @param unicode The character in unicode
     * @return The glyph name
     */
    public static String getNameFromUnicode(final String unicode) {
        return unicodeToName.get(unicode);
    }
    
    public static String  getEncodedChar(final int font_encoding, final int char_int){
        
        String return_character=null;
        
        switch (font_encoding) {
            case WIN:
                return_character=WIN_char_encoding_table[char_int];
                break;
            case STD:
                return_character=STD_char_encoding_table[char_int];
                break;
            case MAC:
                return_character=MAC_char_encoding_table[char_int];
                break;
            case PDF:
                return_character=PDF_char_encoding_table[char_int];
                break;
            case ZAPF:
                return_character=ZAPF_char_encoding_table[char_int];
                break;
            case SYMBOL:
                return_character=SYMBOL_char_encoding_table[char_int];
                break;
            case MACEXPERT:
                return_character=MACEXPERT_char_encoding_table[char_int];
                break;
            default:
                break;
        }
        
        if (return_character== null) {
            return_character = "&#" + char_int + ';';
        }
        
        return return_character;
    }
    
    /**load required mappings*/
    public  static void checkLoaded( final int enc) {
        
        
        /*load mapping if we need it and initialise storage*/
        if((enc==MAC)&&(MAC_char_encoding_table==null)){
            
            MAC_char_encoding_table = new String[335];
            readStandardMappingTable(enc);
            
        }else if((enc== WIN)&&(WIN_char_encoding_table==null)){
            
            WIN_char_encoding_table = new String[335];
            readStandardMappingTable(enc);
            
        }else if((enc==STD)&&(STD_char_encoding_table==null)){
            
            STD_char_encoding_table = new String[335];
            readStandardMappingTable(enc);
            
        }else if((enc==PDF)&&(PDF_char_encoding_table==null)){
            
            PDF_char_encoding_table = new String[335];
            readStandardMappingTable(enc);
            
        }else if((enc==SYMBOL)&&(SYMBOL_char_encoding_table==null)){
            
            SYMBOL_char_encoding_table = new String[335];
            readStandardMappingTable(SYMBOL, "symbol.cfg");
            
        }else if((enc==ZAPF)&&(ZAPF_char_encoding_table==null)){
            
            ZAPF_char_encoding_table = new String[335];
            readStandardMappingTable(ZAPF, "zapf.cfg");
            
        }else if((enc==MACEXPERT)&&(MACEXPERT_char_encoding_table==null)){
            
            MACEXPERT_char_encoding_table = new String[335];
            readStandardMappingTable(MACEXPERT, "mac_expert.cfg");
            
        }
    }
    
    /////////////////////////////////////////////////////////////////////////
    /**
     * read default widths for 14 standard fonts supplied
     * by Adobe
     */
    static final synchronized void loadStandardFont(final int i) throws IOException{
        String line, next_command, char_name = "";
        final BufferedReader input_stream;
        float width = 200;
        //int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
        //int b_x1 = 0, b_y1 = 0, b_x2 = 0, b_y2 = 0;
        
        //allow for 2 calls on thread with second call stalling this so
        //we should exit
        if(standardFontLoaded.get(i)!=null) {
            return;
        }
        
        // loop to read widths from default fonts
        {
        //open the file
        input_stream =
                new BufferedReader(
                        new InputStreamReader(
                                loader.getResourceAsStream(
                                        "org/jpedal/res/pdf/defaults/"
                                                + files_names[i]
                                                + ".afm"),
                                enc));
        
        boolean char_mapping_table = false;
        //flag if in correct part of file
        while (true) { //read the lines and extract width info
            line = input_stream.readLine();
            
            if (line == null) {
                break;
            }
            if (line.startsWith("EndCharMetrics")) {
                char_mapping_table = false;
            }
            
            //extract bounding box
            if (line.startsWith("FontBBox")) {
                
                final float[] fontBBox=new float[4];
                final StringTokenizer values = new StringTokenizer(line);
                //drop FontBBox
                values.nextToken();
                
                for(int a=0;a<4;a++) {
                    fontBBox[a] = Integer.parseInt(values.nextToken());
                }
                
                fontBounds.put(files_names[i],fontBBox);
                
                
            }
            
            if (char_mapping_table) { //extract info from the line
                final StringTokenizer values = new StringTokenizer(line, " ;");
                
                //extract values
                while (values.hasMoreTokens()) {
                    next_command = values.nextToken();
                    if (next_command.equals("WX")) {
                        width = Float.parseFloat(values.nextToken()) / 1000;
                    } else if (next_command.equals("N")) {
                        char_name = values.nextToken();
                    }
                }
                
                //store width
                widthTableStandard.put(files_names_bis[i].toLowerCase() + char_name, width);
                widthTableStandard.put(files_names[i].toLowerCase()  + char_name, width);
                
            }
            if (line.startsWith("StartCharMetrics")) {
                char_mapping_table = true;
            }
        }
    }
        
        if(input_stream!=null){
            try{
                input_stream.close();
            }catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " reading lookup table for pdf  for abobe map");
            }
        }
        
        //flag value is set
        standardFontLoaded.put(i,"x");
    }
    
    /**
     * check if one of 14 standard fonts and if so load widths
     */
    protected static void loadStandardFontWidth(final String fontName){
        
        //get name of font if standard
        final Integer fileNumber= standardFileList.get(fontName);
        
        
        if( fileNumber!=null && standardFontLoaded.get(fileNumber)==null){
            
            try{
                loadStandardFont(fileNumber);
                
            } catch (final Exception e) {
                LogWriter.writeLog("[PDF] " + e + " problem reading lookup table for pdf font "+fontName+ ' ' +fontName);
            }
        }
    }
    
    /**
     * converts glyph into character index
     */
    public static int lookupCharacterIndex(final String glyph, final int idx) {
        
        final Object value=glyphToChar[idx].get(glyph);
        if(value==null) {
            return 0;
        } else {
            return (Integer) value;
        }
    }
    
    /**
     * load the adobe unicode mapping table for truetype fonts
     */
    private static void loadAdobeMap() {
        
        BufferedReader input_stream =null;
        
        /*load if not already loaded*/
        if(adobeMap==null){
            try {
                //initialise
                adobeMap=new HashMap();
                
                input_stream =new BufferedReader(
                        new InputStreamReader(
                                loader.getResourceAsStream(
                                        "org/jpedal/res/pdf/glyphlist.cfg"),
                                enc));
                
                // trap problems
                if (input_stream == null) {
                    LogWriter.writeLog("Unable to open glyphlist.cfg from jar");
                }
                
                //read in lines and place in map tables for fast lookup
                while (true) {
                    final String line = input_stream.readLine();
                    if (line == null) {
                        break;
                    }
                    
                    if((!line.startsWith("#"))&&(line.indexOf(';')!=-1)){
                        
                        final StringTokenizer vals=new StringTokenizer(line,";");
                        final String key=vals.nextToken();
                        String operand=vals.nextToken();
                        final int space=operand.indexOf(' ');
                        if(space!=-1) {
                            operand=operand.substring(0,space);
                        }
                        final int opVal=Integer.parseInt(operand,16);
                        adobeMap.put(key, opVal);
                        
                        unicode_name_mapping_table.put(key,Character.toString((char)opVal));
                        
                    }
                }
            } catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " reading lookup table for pdf  for abobe map");
            }
        }
        
        if(input_stream!=null){
            try{
                input_stream.close();
            }catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " reading lookup table for pdf  for abobe map");
            }
        }    
    }
    /**
     * @return Returns the adobe mapping for truetype case 3,1
     */
    public static int getAdobeMap(final String key){
        
        final Integer value=adobeMap.get(key);
        if(value==null) {
            return -1;
        } else {
            return value;
        }
        
    }
    
    /**
     * @return Returns a boolean if in Adobe map
     */
    public static boolean isValidGlyphName(final String key){
        
        if(key==null) {
            return false;
        } else {
            return(adobeMap.get(key)!=null);
        }
        
    }
    
    
    /**
     * see if a standard font (ie Arial, Helvetica)
     */
    public static boolean isStandardFont(final String fontName, final boolean excludeWeights) {
        
        boolean isStandard = (standardFileList.get(fontName) != null);

        if (!isStandard && excludeWeights) {

            final char[] valuesToTest = {'-', ','};
            for (char valueToTest : valuesToTest) {

                isStandard = checkSubFontName(fontName, valueToTest);
                if (isStandard) {
                    break;
                }
            }
        }
        return isStandard;
    }

    private static boolean checkSubFontName(final String fontName, final char charToTest) {
        
        boolean isStandard=false;
        
        final int ptr=fontName.indexOf(charToTest);
        if(ptr!=-1){
            isStandard=(standardFileList.get(fontName.substring(0,ptr))!=null);
        }
        return isStandard;
    }
    
    /**
     * open font , read postscript, and return Map with font details
     */
    public static Map getFontDetails(final int type, final String subFont) {
        
        final Map fontDetails=new HashMap();
        
        /*read in font data*/
        if(type==TRUETYPE || type==TRUETYPE_COLLECTION){
            
            //FontData closed in routine
            TTGlyphs.addStringValues(new FontData(subFont), fontDetails);
            
        }
        
        return fontDetails;
    }
    
    /**
     * open font , read postscript, family or full names and return array
     */
    public static String[] readNamesFromFont(final int type, final String subFont, final int mode) throws Exception {
        
        String[] fontNames=new String[1];
        fontNames[0]="";
        
        
        /*read in font data*/
        if(type==TRUETYPE || type==TRUETYPE_COLLECTION){
            
            //FontData closed in routine
            fontNames= TTGlyphs.readFontNames(new FontData(subFont), mode);
            
        }else if(type==TYPE1){
            
            //FontData closed in routine
            fontNames= T1Glyphs.readFontNames(new FontData(subFont));
            
        }
        
        return fontNames;
    }
    
    //allow for number value as well as glyph name (ie 68 rather than D)
    public static String convertNumberToGlyph(String mappedChar, final boolean containsHexNumbers, final boolean allowSingleValue) {
        
        int charCount=mappedChar.length();
        
        boolean isNumber=true; //assume true and disprove
        
        //System.out.println(mappedChar+" "+containsHexNumbers);
        
        /**/
        boolean hasHex=false;
        if(charCount==2 || charCount==3 || (allowSingleValue && charCount==1)){
            for(int ii=0;ii='0' && c<='9'){
                }else if(containsHexNumbers && c>='A' && c<='F'){
                    hasHex=true;
                }else{  //fail on first and exit loop
                    isNumber=false;
                    ii=charCount;
                }
            }
            
            if(isNumber){
                
                if(charCount==3 || !containsHexNumbers){
                    if(!hasHex) { //stop spurious match (ie DC1)
                        mappedChar= String.valueOf((char) Integer.parseInt(mappedChar));
                    }
                }else{
                    mappedChar= String.valueOf((char) Integer.parseInt(mappedChar,16));
                }
            }
        }else{ //check any hash values to fix odd bug in file where #2323 truncates to #23
            boolean hasHash=false,hasText=false;
            
            for(int ii=0;ii='A' && c<='Z') {
                    hasText=true;
                }
            }
            
            if(hasHash){
                
                final StringBuilder buf=new StringBuilder(mappedChar);
                
                //if text as well replicate what seems to happen in Acrobat and remove number value
                if(hasText){
                    
                    try{
                        //System.out.println("before="+buf.toString());
                        
                        for(int ii=0;ii=charCount)
                                    //     break;
                                }
                            }
 
                    }catch(final Exception e){
                        LogWriter.writeLog("Exception: "+e.getMessage());
                    }
                }else{
                    for(int ii=0;ii='0' && c2<='9'){
                                    buf.deleteCharAt(ii);
                                    charCount--;
                                    
                                    if(ii>=charCount) {
                                        break;
                                    }
                                    
                                    c2=buf.charAt(ii);
                                }
                            }
                            ii--;
                        }
                    }
                }
                
                mappedChar=buf.toString();
                
            }
        }
        
        return mappedChar;
    }
    
    /**
     * turn hashed key value into String
     */
    public static String getFontypeAsString(final int fontType) {
        switch(fontType){
            
            case TRUETYPE:
                return "TrueType";
            case TYPE1:
                return "Type1";
            case TYPE3:
                return "Type3";
                
            case CIDTYPE0:
                return "CIDFontType0";
            case CIDTYPE2:
                return "CIDFontType2";
                
            default:
                return "Unknown";
        }
    }
    
    
    private static final HashMap> mappedCharacters = new HashMap>();
    private static final HashMap> takenChars = new HashMap>();
    private static final int MAX_CHAR_CODE = 0xD800;
    
    private static void blockForbiddenRanges(final ArrayList ids) {
        int i;
        
        for (i=0x0; i<=0x1f; i++) {
            ids.add(i);
        }
        
        for (i=0x7f; i<=0xa0; i++) {
            ids.add(i);
        }
        
        for (i=0x200c; i<=0x200f; i++) {
            ids.add(i);
        }
        
    }
    /**
     * Find an appropriate value to use for identity CID fonts as unicode values are unrelated to actual values and many
     * potential values are blocked by browsers
     * @param fontName Name of the font to use
     * @param cid The cid value to map from
     * @return The value mapped onto
     */
    public static int mapCIDToValidUnicode(final String fontName, final int cid) {
        
        HashMap cidMap = mappedCharacters.get(fontName);
        ArrayList taken = takenChars.get(fontName);
        
        //Create structures for this font if they don't exist yet
        if (cidMap == null) {
            cidMap = new HashMap();
            mappedCharacters.put(fontName, cidMap);
            
            taken = new ArrayList();
            takenChars.put(fontName, taken);
            
            blockForbiddenRanges(taken);
        }
        
        //Fetch mapping and return if present
        final Integer result = cidMap.get(cid);
        if (result != null) {
            return result;
        }
        
        //First try existing CID
        int newCid = cid;
        
        //If under 0x20 shift by 0x20 to try to get reasonable extraction
        if (cid < 0x20) {
            newCid += 0x20;
        }
        
        //Otherwise use first available CID
        while (taken.contains(newCid) && taken.size() < MAX_CHAR_CODE) {
            newCid = (newCid+1)%MAX_CHAR_CODE;
        }
        
        //Store for later lookup
        cidMap.put(cid,newCid);
        taken.add(newCid);
        
        return newCid;
    }
    
    
    public static int getIDForGlyphName(final String fontName, String glyphName) {
        boolean base10=false;
        final int uc = getAdobeMap(glyphName);
        if (uc >= 0) {
            return uc;
        } else if (glyphName.startsWith("uni")){
            glyphName = glyphName.substring(3);
        } else if (glyphName.charAt(0) == 'u' || glyphName.charAt(0) == 'G'){
            glyphName = glyphName.substring(1);
        } else {
            base10 = true;
        }

        if (glyphName != null) {
            try {
                if (base10 && glyphName.matches("[0-9]+")) {
                    int num = Integer.parseInt(glyphName, 10);
                    return mapCIDToValidUnicode(fontName, num);
                } else if (glyphName.matches("[0-9A-F]+")) {
                    return Integer.parseInt(glyphName, 16);
                }
            } catch (final NumberFormatException e) {
                LogWriter.writeLog("Exception in handling cid id "+e);
            }
        }

        return -1;
    }
    
    /**
     * convert common abbreviations of standard fonts names
     */
    public static String expandName(String name) {
        
        final String testName=name.toLowerCase();
        
        if(testName.equals("cour")) {
            name="Courier";
        } else if(testName.equals("helv")) {
            name="Helvetica";
        } else if(testName.equals("hebo")) {
            name="Helvetica-BOLD";
        } else if(testName.equals("zadb")) {
            name="ZapfDingbats";
        } else if(testName.equals("tiro")){
            name="Times";
        }
        
        return name;
    }
    
    public static String[] CMAP;
    
    public static void readCMAP() {
        
        //initialise first time and use as flag to show read
        CMAP=new String[65536];
        
        String line;
        int rawVal,unicodeVal;
        final BufferedReader input_stream;
        
        try {
            
            input_stream =new BufferedReader(
                    new InputStreamReader(loader.getResourceAsStream("org/jpedal/res/pdf/jis.cfg")));
            
            
            //read in lines and place in map tables for fast lookup
            while (true) {
                line = input_stream.readLine();
                if (line == null) {
                    break;
                }
                
                if(line.startsWith("0") && line.contains("#")){
                    
                    
                    //write values to table, converting from Octal
                    final StringTokenizer values = new StringTokenizer(line);
                    //System.out.println(line);
                    final String xx=values.nextToken().substring(2);
                    
                    rawVal=Integer.parseInt(xx,16);//raw hex
                    //values.nextToken();//ignore
                    unicodeVal=Integer.parseInt(values.nextToken().substring(2),16);//unicode
                    CMAP[rawVal]=String.valueOf((char)unicodeVal);
                }
            }
            
            input_stream.close();
            
        }catch(final Exception e){
            LogWriter.writeLog("Exception: "+e.getMessage());
        }
    }    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy