org.jpedal.fonts.StandardFonts Maven / Gradle / Ivy
The newest version!
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/java-pdf-library-support/
*
* (C) Copyright 1997-2013, IDRsolutions and Contributors.
*
* This file is part of JPedal
*
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.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
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 {
// Enable to test new CID extraction code
public final static boolean samsCIDExtractionCode = true;
/** holds names of every character */
static private 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 final static int PDF = 6;
/** flag used to identify ZAPF encoding */
public final static int ZAPF = 5;
/** flag used to identify Symbol encoding */
public final static int SYMBOL = 4;
/** flag used to identify MacExpert encoding */
public final static int MACEXPERT = 3;
/** flag used to identify WIN encoding */
public final static int WIN = 2;
/** flag used to identify STD encoding */
public final static int STD = 1;
/** flag used to identify mac encoding */
public final static int MAC = 0;
/** mapped onto CID0 or CID2 */
final public static int TYPE0 = 1228944676;
public final static int TYPE1 = 1228944677;
public final static int TRUETYPE = 1217103210;
public final static int TYPE3 = 1228944679;
public final static int CIDTYPE0 = -1684566726;
public final static int CIDTYPE2 = -1684566724;
public final static int OPENTYPE = 6;
public final static int TRUETYPE_COLLECTION = 7;
public final static int FONT_UNSUPPORTED = 8;
/** constant value for ellipsis */
private static 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";
/** only in 1 encoding */
private static Map uniqueValues = null;
/** 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;
/** 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 */
private static Map widthTableStandard = new HashMap();
private static Map adobeCMAPS = null;
/** names of CID fonts supplied by Adobe */
private static String[] CIDFonts = { "83pv-RKSJ-H", "90msp-RKSJ-H", "90msp-RKSJ-V", "90ms-RKSJ-H", "90ms-RKSJ-UCS2", "90ms-RKSJ-V",
"90pv-RKSJ-H", "90pv-RKSJ-UCS2", "90pv-RKSJ-UCS2C", "Add-RKSJ-H", "Add-RKSJ-V", "Adobe-CNS1-3", "Adobe-CNS1-UCS2", "Adobe-GB1-4",
"Adobe-GB1-UCS2", "Adobe-Japan1-4", "Adobe-Japan1-UCS2", "Adobe-Korea1-2", "Adobe-Korea1-UCS2", "B5pc-H", "B5pc-UCS2", "B5pc-UCS2C",
"B5pc-V", "CNS-EUC-H", "CNS-EUC-V", "ETen-B5-H", "ETen-B5-UCS2", "ETen-B5-V", "euc-h", "euc-v", "Ext-RKSJ-H", "Ext-RKSJ-V", "gb-euc-h",
"gb-euc-v", "gbk2k-h", "gbk2k-v", "GBK-EUC-H", "GBK-EUC-UCS2", "GBK-EUC-V", "GBKp-EUC-H", "GBKp-EUC-V", "GBpc-EUC-H", "GBpc-EUC-UCS2",
"GBpc-EUC-UCS2C", "GBpc-EUC-V", "GBT-EUC-H", "GBT-EUC-V", "h", "HKscs-B5-H", "HKscs-B5-V", "KSC-EUC-H", "KSC-EUC-V", "KSCms-UHC-H",
"KSCms-UHC-HW-H", "KSCms-UHC-HW-V", "KSCms-UHC-UCS2", "KSCms-UHC-V", "KSCpc-EUC-H", "KSCpc-EUC-UCS2", "KSCpc-EUC-UCS2C", "UniCNS-UCS2-H",
"UniCNS-UCS2-V", "UniGB-UCS2-H", "UniGB-UCS2-V", "UniJIS-UCS2-H", "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V", "UniJIS-UCS2-V",
"UniKS-UCS2-H", "UniKS-UCS2-V", "v" };/**/
/** 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", "ZapfDingbats" };
/** holds lookup values used by truetype font mapping */
private static HashMap adobeMap = null;
// hold bounds
private static Map fontBounds = new HashMap();
/** flag if standard_encoding loaded */
public static boolean usesGlyphlist = false;
public static void dispose() {
unicode_name_mapping_table = null;
unicode_char_decoding_table = null;
uniqueValues = 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(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(String fontName) {
return (float[]) fontBounds.get(fontName);
}
public static String getUnicodeName(String key) {
return (String) unicode_name_mapping_table.get(key);
}
public static String getUnicodeChar(int i, int key) {
return unicode_char_decoding_table[i][key];
}
public static Map getUniqueMappings() {
if (uniqueValues == null) {
uniqueValues = new HashMap();
for (int ii = 0; ii < 256; ii++) {
if (WIN_char_encoding_table[ii] == null && MAC_char_encoding_table[ii] != null) {
// System.out.println(ii+" MAC only="+MAC_char_encoding_table[ii]);
uniqueValues.put(ii, 1);
}
if (WIN_char_encoding_table[ii] != null && MAC_char_encoding_table[ii] == null) {
// System.out.println(ii+" WIN only="+WIN_char_encoding_table[ii]);
uniqueValues.put(ii, -1);
}
}
}
return uniqueValues;
}
public static Float getStandardWidth(String font, String key) {
Object value = widthTableStandard.get(font + key);
if (value == null) {
String altfont = font;
int p = altfont.indexOf(',');
if (p != -1) {
altfont = altfont.substring(0, p);
value = widthTableStandard.get(altfont + key);
}
}
return (Float) value;
}
// ////////////////////////////////////////////////////////////////////////
/**
* create mapping tables for pdf values for Zapf and Symbol (not fully implmented yet)
*/
final static private void readStandardMappingTable(int key, 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.isOutput()) {
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
StringTokenizer values = new StringTokenizer(line);
// trap for space and lines which cause problems in Zapf
if ((!line.contains("space")) && (values.countTokens() > 1)) {
// ignore first as token but read as char
if (values.countTokens() == 3) {
char_value = values.nextToken();
NAME = values.nextToken();
VAL = values.nextToken();
}
else
if (values.countTokens() == 4) {
hexVal = values.nextToken();
// noinspection UnusedAssignment
char_value = values.nextToken();
NAME = values.nextToken();
VAL = values.nextToken();
char_value = Character.toString((char) Integer.parseInt(hexVal, 16));
}
else { // zapf values
if (values.countTokens() == 2) {
char_value = " ";
NAME = values.nextToken();
VAL = values.nextToken();
}
else {
char_value = values.nextToken();
NAME = values.nextToken();
VAL = values.nextToken();
}
}
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"))
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 (Exception e) {
if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " reading lookup table for pdf");
}
if (input_stream != null) {
try {
input_stream.close();
}
catch (Exception e) {
if (LogWriter.isOutput()) 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
*/
final static private void readStandardMappingTable(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.isOutput()) 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
StringTokenizer values = new StringTokenizer(line);
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;
// 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 (Exception e) {
if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " reading lookup table for pdf for " + idx);
}
if (input_stream != null) {
try {
input_stream.close();
}
catch (Exception e) {
if (LogWriter.isOutput()) 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; }
*/
static public String getEncodedChar(int font_encoding, int char_int) {
String return_character = null;
if (font_encoding == WIN) return_character = WIN_char_encoding_table[char_int];
else
if (font_encoding == STD) return_character = STD_char_encoding_table[char_int];
else
if (font_encoding == MAC) return_character = MAC_char_encoding_table[char_int];
else
if (font_encoding == PDF) return_character = PDF_char_encoding_table[char_int];
else
if (font_encoding == ZAPF) return_character = ZAPF_char_encoding_table[char_int];
else
if (font_encoding == SYMBOL) return_character = SYMBOL_char_encoding_table[char_int];
else
if (font_encoding == MACEXPERT) return_character = MACEXPERT_char_encoding_table[char_int];
if (return_character == null) return_character = "" + char_int + ';';
return return_character;
}
/** flag fi a valid mac char - must have loaded mac encoding */
public static boolean isValidMacEncoding(int idx) {
// if(MAC_char_encoding_table[idx]!=null)
// System.out.println("mac="+MAC_char_encoding_table[idx]);
return MAC_char_encoding_table[idx] != null;
}
/** flag fi a valid win char - must have loaded win encoding */
public static boolean isValidWinEncoding(int idx) {
// if(WIN_char_encoding_table[idx]!=null)
// System.out.println("win="+WIN_char_encoding_table[idx]);
return WIN_char_encoding_table[idx] != null;
}
/** load required mappings */
public static void checkLoaded(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
*/
final private static void loadStandardFont(int i) throws IOException {
String line, next_command, char_name = "";
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;
// 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")) {
float[] fontBBox = new float[4];
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 == true) { // extract info from the line
StringTokenizer values = new StringTokenizer(line, " ;");
// extract values
while (values.hasMoreTokens()) {
next_command = values.nextToken();
/**
* if (next_command.equals("C")) char_number = values.nextToken();
*/
if (next_command.equals("WX")) width = Float.parseFloat(values.nextToken()) / 1000;
else
if (next_command.equals("N")) char_name = values.nextToken();
/**
* if (next_command.equals("B")) { x1 = Integer.parseInt(values.nextToken()); y1 = Integer.parseInt(values.nextToken()); x2 =
* Integer.parseInt(values.nextToken()); y2 = Integer.parseInt(values.nextToken()); }
*/
}
// store width
widthTableStandard.put(files_names_bis[i] + char_name, width);
widthTableStandard.put(files_names[i] + char_name, width);
}
if (line.startsWith("StartCharMetrics")) char_mapping_table = true;
}
}
if (input_stream != null) {
try {
input_stream.close();
}
catch (Exception e) {
if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " reading lookup table for pdf for abobe map");
}
}
}
/**
* check if one of 14 standard fonts and if so load widths
*/
protected static void loadStandardFontWidth(String fontName) {
// get name of font if standard
Integer fileNumber = (Integer) standardFileList.get(fontName);
if (fileNumber != null && standardFontLoaded.get(fileNumber) == null) {
standardFontLoaded.put(fileNumber, "x");
try {
loadStandardFont(fileNumber);
}
catch (Exception e) {
if (LogWriter.isOutput()) LogWriter
.writeLog("[PDF] " + e + " problem reading lookup table for pdf font " + fontName + ' ' + fontName);
}
}
}
/**
* converts glyph into character index
*/
public static int lookupCharacterIndex(String glyph, int idx) {
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.isOutput()) LogWriter.writeLog("Unable to open glyphlist.cfg from jar");
// read in lines and place in map tables for fast lookup
while (true) {
String line = input_stream.readLine();
if (line == null) break;
if ((!line.startsWith("#")) && (line.indexOf(';') != -1)) {
StringTokenizer vals = new StringTokenizer(line, ";");
String key = vals.nextToken();
String operand = vals.nextToken();
int space = operand.indexOf(' ');
if (space != -1) operand = operand.substring(0, space);
int opVal = Integer.parseInt(operand, 16);
adobeMap.put(key, opVal);
unicode_name_mapping_table.put(key, Character.toString((char) opVal));
}
}
}
catch (Exception e) {
if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " reading lookup table for pdf for abobe map");
e.printStackTrace(System.out);
}
}
if (input_stream != null) {
try {
input_stream.close();
}
catch (Exception e) {
if (LogWriter.isOutput()) 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(String key) {
Object value = adobeMap.get(key);
if (value == null) return -1;
else return (Integer) value;
}
/**
* @return Returns a boolean if in Adobe map
*/
public static boolean isValidGlyphName(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(String fontName, boolean includeWeights) {
boolean isStandard = (standardFileList.get(fontName) != null);
if (!isStandard && includeWeights) {
int ptr = fontName.indexOf('-');
if (ptr != -1) {
String rawName = fontName.substring(0, ptr);
// System.out.println(ptr+"<>"+fontName+"<>"+rawName+"<>"+standardFileList.get(fontName)!=null);
isStandard = (standardFileList.get(rawName) != null);
}
}
return isStandard;
}
/**
* open font , read postscript, and return Map with font details
*/
public static Map getFontDetails(int type, String subFont) {
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(int type, String subFont, 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), mode);
}
return fontNames;
}
// allow for number value as well as glyph name (ie 68 rather than D)
public static String convertNumberToGlyph(String mappedChar, boolean containsHexNumbers, boolean allowSingleValue) {
int charCount = mappedChar.length();
boolean isNumber = true; // assume true and disprove
// System.out.println(mappedChar+" "+containsHexNumbers);
if (charCount == 2 || charCount == 3) {
for (int ii = 0; ii < charCount; ii++) { // test all values to see if number
char c = mappedChar.charAt(ii);
if (c < '0' || c > '9') { // fail on first and exit loop
isNumber = false;
ii = charCount;
}
}
if (isNumber) mappedChar = String.valueOf((char) Integer.parseInt(mappedChar));
}
/**/
return mappedChar;
}
/**
* turn hashed key value into String
*/
public static String getFontypeAsString(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 HashMap> mappedCharacters = new HashMap>();
private static HashMap> takenChars = new HashMap>();
private final static int MAX_CHAR_CODE = 0xD800;
private static void blockForbiddenRanges(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(String fontName, 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
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(String fontName, String glyphName) {
boolean base10 = false;
int uc = StandardFonts.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;
}
try {
int num;
if (samsCIDExtractionCode && base10) {
num = Integer.parseInt(glyphName, 10);
num = mapCIDToValidUnicode(fontName, num);
}
else num = Integer.parseInt(glyphName, 16);
return num;
}
catch (NumberFormatException 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 = null;
public static void readCMAP() {
// initialise first time and use as flag to show read
CMAP = new String[65536];
String line;
int rawVal, unicodeVal;
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
StringTokenizer values = new StringTokenizer(line);
// System.out.println(line);
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 (Exception e) {
// tell user and log
if (LogWriter.isOutput()) LogWriter.writeLog("Exception: " + e.getMessage());
}
}
/**
* see if an Adobe CMAP which we store in CID jar
*/
static boolean isAdobeCMAP(String encodingName) {
// lazy intialisation
if (adobeCMAPS == null) {
adobeCMAPS = new HashMap();
for (Object CMAPname : CIDFonts) {
adobeCMAPS.put(CMAPname, "x");
}
}
return adobeCMAPS.containsKey(encodingName);
}
}