org.jpedal.fonts.PdfFont Maven / Gradle / Ivy
/*
* ===========================================
* 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
*
* ---------------
* PdfFont.java
* ---------------
*/
package org.jpedal.fonts;
//standard java
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.io.BufferedReader;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.jpedal.PdfDecoder;
import org.jpedal.exception.PdfFontException;
import org.jpedal.fonts.glyph.PdfJavaGlyphs;
import org.jpedal.io.ObjectStore;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.objects.raw.CIDEncodings;
import org.jpedal.objects.raw.FontObject;
import org.jpedal.objects.raw.PdfArrayIterator;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.utils.LogWriter;
/**
* contains all generic pdf font data for fonts.
*
*
*/
public class PdfFont implements Serializable {
private static final long serialVersionUID = 4000021454599886917L;
PdfObject ToUnicode;
public Font javaFont = null;
private Rectangle BBox = null;
String CMapName = null;
boolean handleOddSapFontMapping = false;
/** used to track if CID font is double byte or not by looking at first 2 values */
boolean isFirstScan = true;
int isDouble = -1; // -1=unset
// value to use if no width set for this
final static private int noWidth = -1;
// workaroud for type3 fonts which contain both Hex and Denary Differences tables
protected boolean containsHexNumbers = false, allNumbers = false;
protected String embeddedFontName = null, embeddedFamilyName = null, copyright = null;
private float missingWidth = noWidth;
boolean isSingleByte = false;
protected boolean isFontVertical = false;
/** cached value for last width value returned */
private float lastWidth = noWidth;
public PdfJavaGlyphs glyphs = new PdfJavaGlyphs();
/** cache for translate values */
private String[] cachedValue = new String[256];
// unmapped font name
private String rawFontName = null;
// used by HTML
private float currentWidth;
// used by HTML to translate non-standard glyfs to correct values
Map nonStandardMappings = new HashMap(256);
public boolean hasDoubleBytes;
static {
setStandardFontMappings();
}
public PdfFont() {}
/** read in a font and its details for generic usage */
public void createFont(String fontName) throws Exception {}
/** get handles onto Reader so we can access the file */
public PdfFont(PdfObjectReader current_pdf_file) {
init(current_pdf_file);
}
private static void setStandardFontMappings() {
int count = StandardFonts.files_names.length;
for (int i = 0; i < count; i++) {
String key = StandardFonts.files_names_bis[i].toLowerCase();
String value = StandardFonts.javaFonts[i].toLowerCase();
if ((!key.equals(value)) && (!FontMappings.fontSubstitutionAliasTable.containsKey(key))) FontMappings.fontSubstitutionAliasTable.put(key,
value);
}
for (int i = 0; i < count; i++) {
String key = StandardFonts.files_names[i].toLowerCase();
String value = StandardFonts.javaFonts[i].toLowerCase();
if ((!key.equals(value)) && (!FontMappings.fontSubstitutionAliasTable.containsKey(key))) FontMappings.fontSubstitutionAliasTable.put(key,
value);
StandardFonts.javaFontList.put(StandardFonts.files_names[i], "x");
}
}
protected String substituteFont = null;
protected boolean renderPage = false;
private static final float xscale = (float) 0.001;
/** embedded encoding */
protected int embeddedEnc = StandardFonts.STD;
/** holds lookup to map char differences in embedded font */
protected String[] diffs;
/** flag to show if Font included embedded data */
public boolean isFontEmbedded = false;
/* show if font stream CID */
protected boolean TTstreamisCID = false;
/** String used to reference font (ie F1) */
protected String fontID = "";
/** number of glyphs - 65536 for CID fonts */
protected int maxCharCount = 256;
/** show if encoding set */
protected boolean hasEncoding = true;
/** font type */
protected int fontTypes;
protected String substituteFontFile = null;
/** lookup to track which char is space. -1 means none set */
private int spaceChar = -1;
/** holds lookup to map char differences */
String[] diffTable;
private int[] diffCharTable;
protected Map diffLookup = null;
/** lookup for which of each char for embedded fonts which we can flush */
private float[] widthTable;
/** size to use for space if not defined (-1 is no setting) */
private float possibleSpaceWidth = noWidth;
/** handle onto file access */
protected PdfObjectReader currentPdfFile;
/** loader to load data from jar */
protected ClassLoader loader = this.getClass().getClassLoader();
/** FontBBox for font */
public double[] FontMatrix = { 0.001d, 0d, 0d, 0.001d, 0, 0 };
/** font bounding box */
public float[] FontBBox = { 0f, 0f, 1000f, 1000f };
float ascent = 0;
float descent = 0;
/**
* flag to show Gxxx, Bxxx, Cxxx.
*/
protected boolean isHex = false;
/** holds lookup to map char values */
private String[] unicodeMappings;
/** encoding pattern used for font. -1 means not set */
protected int fontEnc = -1;
/** flag to show type of font */
protected boolean isCIDFont = false;
/** lookup CID index mappings */
private String[] CMAP;
/** CID font encoding */
private String CIDfontEncoding;
/** default width for font */
private float defaultWidth = 1f;
protected boolean isFontSubstituted = false;
protected int italicAngle = 0;
boolean hasMatrixSet = false, hasFBoxSet = false;
private byte[] stream;
private int[] CIDToGIDMap;
/** test if cid.jar present first time we need it */
private static boolean isCidJarPresent;
/**
* used to show truetype used for type 0 CID
*/
public boolean isFontSubstituted() {
return this.isFontSubstituted;
}
/** Method to add the widths of a CID font */
private void setCIDFontWidths(String values) {
// remove first and last []
values = values.substring(1, values.length() - 1).trim();
// trap for empty values
if (values.length() == 0) return;
this.widthTable = new float[65536];
// set all values to -1 so I can spot ones with no value
for (int ii = 0; ii < 65536; ii++)
this.widthTable[ii] = noWidth;
StringTokenizer widthValues = new StringTokenizer(values, " []", true);
String currentValue = "", lastValue = "", nextValue = "";
int pointer = 0, lastPointer = 0;
while (widthValues.hasMoreTokens()) {
nextValue = widthValues.nextToken();
if (!nextValue.equals(" ")) break;
}
boolean isDone = false;
while (true) {
if (isDone) break;
if (nextValue.equals("R")) { // allow for special odd case 0 1449 0 R and read data directly
String ref = lastValue + ' ' + currentValue + " R";
int number = Integer.parseInt(lastValue);
int generation = Integer.parseInt(currentValue);
pointer = lastPointer;
// get the list directly from 14449 0 R
FontObject widthObj = new FontObject(ref);
byte[] data = this.currentPdfFile.getObjectReader().readObjectAsByteArray(widthObj,
this.currentPdfFile.getObjectReader().isCompressed(number, generation), number, generation);
// and parse
StringTokenizer widthValues2 = new StringTokenizer(new String(data), " []");
String val;
while (widthValues2.hasMoreTokens()) {
val = widthValues2.nextToken();
this.widthTable[pointer] = Float.parseFloat(val) / 1000f;
pointer++;
}
// read next value
if (widthValues.hasMoreTokens()) {
while (widthValues.hasMoreTokens()) {
nextValue = widthValues.nextToken();
if (!nextValue.equals(" ")) break;
}
}
else isDone = true;
}
else {
lastValue = currentValue;
currentValue = nextValue;
lastPointer = pointer;
pointer = Integer.parseInt(currentValue);
while (true) {
currentValue = widthValues.nextToken();
if (!currentValue.equals(" ")) break;
}
// process either range or []
if (currentValue.equals("[")) {
while (true) {
while (true) {
currentValue = widthValues.nextToken();
if (!currentValue.equals(" ")) break;
}
if (currentValue.equals("]")) break;
this.widthTable[pointer] = Float.parseFloat(currentValue) / 1000f;
pointer++;
}
if (widthValues.hasMoreTokens()) {
while (widthValues.hasMoreTokens()) {
nextValue = widthValues.nextToken();
if (!nextValue.equals(" ")) break;
}
}
else isDone = true;
}
else {
int endPointer = 1 + Integer.parseInt(currentValue);
lastValue = currentValue;
while (true) {
currentValue = widthValues.nextToken();
if (!currentValue.equals(" ")) break;
}
if (widthValues.hasMoreTokens()) {
while (true && widthValues.hasMoreTokens()) {
nextValue = widthValues.nextToken();
if (!nextValue.equals(" ")) break;
}
}
else isDone = true;
if (!nextValue.equals("R")) {
for (int ii = pointer; ii < endPointer; ii++)
this.widthTable[ii] = Float.parseFloat(currentValue) / 1000f;
}
}
}
}
}
/** flag if CID font */
final public boolean isCIDFont() {
return this.isCIDFont;
}
/** set number of glyphs to 256 or 65536 */
final protected void init(PdfObjectReader current_pdf_file) {
this.currentPdfFile = current_pdf_file;
// setup font size and initialise objects
if (this.isCIDFont) this.maxCharCount = 65536;
this.glyphs.init(this.maxCharCount, this.isCIDFont);
}
/** return unicode value for this index value */
final public String getUnicodeMapping(int char_int) {
if (this.unicodeMappings == null) return null;
else return this.unicodeMappings[char_int];
}
/** store encoding and load required mappings */
final protected void putFontEncoding(int enc) {
if (enc == StandardFonts.WIN && getBaseFontName().equals("Symbol")) {
putFontEncoding(StandardFonts.SYMBOL);
enc = StandardFonts.SYMBOL;
}
/** save encoding */
this.fontEnc = enc;
StandardFonts.checkLoaded(enc);
}
/** return the mapped character */
final public String getUnicodeValue(String displayValue, int rawInt) {
String textValue = getUnicodeMapping(rawInt);
if (textValue == null) textValue = displayValue;
// map out lignatures
if (displayValue.length() > 0) {
int displayChar = displayValue.charAt(0);
switch (displayChar) {
case 173:
if (this.fontEnc == StandardFonts.WIN || this.fontEnc == StandardFonts.STD) textValue = "-";
break;
case 64256:
textValue = "ff";
break;
case 64257:
textValue = "fi";
break;
case 64260:
textValue = "ffl";
break;
}
}
return textValue;
}
/**
* convert value read from TJ operand into correct glyph
* Also check to see if mapped onto unicode value
*/
final public String getGlyphValue(int rawInt) {
if (this.cachedValue[rawInt] != null) return this.cachedValue[rawInt];
String return_value = null;
if (this.isCIDFont) {
// test for unicode
String unicodeMappings = getUnicodeMapping(rawInt);
if (unicodeMappings != null) return_value = unicodeMappings;
if (return_value == null) {
// get font encoding
String fontEncoding = this.CIDfontEncoding;
if (this.diffTable != null) {
return_value = this.diffTable[rawInt];
}
else
if (fontEncoding != null) {
if (fontEncoding.startsWith("Identity-")) {
return_value = String.valueOf((char) rawInt);
}
else
if (this.CMAP != null) {
String newChar = this.CMAP[rawInt];
if (newChar != null) return_value = newChar;
}
// probably a bit of a hack to fix
// /PDFdata/baseline_screens/customers-dec2012/de0009797407_factsheets_b2c-voll_de_de_31102012_1360767414.pdf
}
else
if (fontEncoding == null && this.CMAP != null && this.CMapName != null && !this.CMapName.endsWith("-V")
&& !this.CMapName.endsWith("-H")) {
String newChar = this.CMAP[rawInt];
if (newChar != null) return_value = newChar;
}
if (return_value == null) return_value = String.valueOf(((char) rawInt));
}
}
else return_value = getStandardGlyphValue(rawInt);
// save value for next time
this.cachedValue[rawInt] = return_value;
return return_value;
}
/**
* read translation table
*
* @throws PdfFontException
*/
final private String handleCIDEncoding(PdfObject Encoding, PdfObject fontObject) throws PdfFontException {
BufferedReader CIDstream = null;
int encodingType = Encoding.getGeneralType(PdfDictionary.Encoding);
String encodingName = CIDEncodings.getNameForEncoding(encodingType);
// see if any general value (ie /UniCNS-UTF16-H not predefined in spec)
if (encodingName == null) {
if (encodingType == PdfDictionary.Identity_H) encodingName = "Identity-H";
else
if (encodingType == PdfDictionary.Identity_V) {
encodingName = "Identity-V";
this.isFontVertical = true;
}
else encodingName = Encoding.getGeneralStringValue();
}
this.CMapName = Encoding.getName(PdfDictionary.CMapName);
if (this.CMapName != null) {
this.stream = this.currentPdfFile.readStream(Encoding, true, true, false, false, false,
Encoding.getCacheName(this.currentPdfFile.getObjectReader()));
encodingName = this.CMapName;
String CMAPstream=new String(this.stream);
CMAPstream=CMAPstream.replaceAll(" begincidchar ", "\nbegincidchar\n");
CMAPstream=CMAPstream.replaceAll(" endcidchar", "\nendcidchar");
CMAPstream=CMAPstream.replaceAll(" begincidrange ", "\begincidrange\n");
CMAPstream=CMAPstream.replaceAll(" endcidrange", "\nendcidrange");
CIDstream=new BufferedReader(new StringReader(CMAPstream));
}
boolean isIdentity = (encodingType == PdfDictionary.Identity_H || encodingType == PdfDictionary.Identity_V);
// System.out.println("Name="+encodingName+" "+encodingType);
/** allow for odd file created by SAP */
// baseline_screens/idoq/UAT 9001001438 INV_I58234.pdf
if (!isIdentity && fontObject != null) {
String name = fontObject.getName(PdfDictionary.BaseFont);
if (name != null && name.contains("Identity")) {
isIdentity = true;
this.handleOddSapFontMapping = true;
this.isSingleByte = true;
}
}
// investigate for daeja/Armando
// flag up some single file CIDs (bit of a hack for the moment)
// if(encodingType==CIDEncodings.CMAP_90ms_RKSJ_H){
// isSingleByte=true;
// }
/** put encoding in lookup table */
if (CIDstream == null) this.CIDfontEncoding = encodingName;
/**
* if not 2 standard encodings load CMAP
*/
if (isIdentity) {
this.glyphs.setIsIdentity(true);
}
else {
// there are a large number of CMAP vtables provided by Adobe which I have put in cid.jar
// this code detects if present and reads the required table
// I also put a font in cid.jar which I think is probably a mistake now (we do not need it)
// test if cid.jar present on first time needed and throw exception if not
// if(!isCidJarPresent && CIDstream==null && StandardFonts.isAdobeCMAP(encodingName)){
// isCidJarPresent=true;
//
// try{
// InputStream in=PdfFont.class.getResourceAsStream("/org/jpedal/res/cid/00_ReadMe.pdf");
// if(in==null){
// throw new PdfFontException("cid.jar not on classpath");
// }
// }catch(SecurityException ee){
// if(LogWriter.isOutput()){
// LogWriter.writeLog("Security exception "+ee+" cid.jar");
// }
// }
// }
this.glyphs.setIsIdentity(false);
this.CMAP = new String[65536];
this.glyphs.CMAP_Translate = new int[65536];
// load standard if not embedded
// try{
// 20120718 commented out by Mark as cid.jar now works (and breaks existing files like customers3/japanese.pdf)
// if(CIDstream==null)
// CIDstream =new BufferedReader
// (new InputStreamReader(loader.getResourceAsStream("org/jpedal/res/cid/" + encodingName), "Cp1252"));
// } catch (Exception e) {
// e.printStackTrace(System.out);
// if(LogWriter.isOutput())
// LogWriter.writeLog("1.Problem reading encoding for CID font "+fontID+" encoding="+encodingName+" Check CID.jar installed");
// }
// read values into lookup table
if (CIDstream != null) {
readCIDCMap(CIDstream);
}
}
if (CIDstream != null) {
try {
CIDstream.close();
}
catch (Exception e) {
if (LogWriter.isOutput()) LogWriter.writeLog("2.Problem reading encoding for CID font " + this.fontID + ' ' + encodingName
+ " Check CID.jar installed");
}
}
return this.CMapName;
}
private void readCIDCMap(BufferedReader CIDstream) {
String line = "";
int begin, end, entry;
boolean inDefinition = false, inMap = false;
while (true) {
try {
line = CIDstream.readLine();
// System.out.println(line);
}
catch (Exception e) {
if (LogWriter.isOutput()) LogWriter.writeLog("[PDF] Error reading line from font");
}
if (line == null) break;
if (line.contains("endcidrange")) inDefinition = false;
else
if (line.contains("endcidchar")) inMap = false;
if (inDefinition == true) {
StringTokenizer CIDentry = new StringTokenizer(line, " <>[]");
// flag if multiple values
boolean multiple_values = false;
if (line.indexOf('[') != -1) multiple_values = true;
// first 2 values define start and end
begin = Integer.parseInt(CIDentry.nextToken(), 16);
end = Integer.parseInt(CIDentry.nextToken(), 16);
// can be hex or base10
String value = CIDentry.nextToken();
int charCount = value.length();
// assume false and try to disprove - exit on first hex char
boolean isHex = false;
for (int ptr = 0; ptr < charCount; ptr++) {
char c = value.charAt(ptr);
if (c >= 48 && c <= 57) {}
else {
isHex = true;
ptr = charCount;
}
}
if (isHex) {
entry = Integer.parseInt(value, 16);
}
else entry = Integer.parseInt(value, 10);
// put into array
for (int i = begin; i < end + 1; i++) {
if (multiple_values == true) {
// put either single values or range
entry = Integer.parseInt(CIDentry.nextToken(), 16);
this.CMAP[i] = String.valueOf((char) entry);
}
else {
this.CMAP[i] = String.valueOf((char) entry);
entry++;
}
}
}
else
if (inMap == true) {
try {
StringTokenizer CIDentry = new StringTokenizer(line, " <>[]");
// System.out.println("line="+line+" "+CIDentry.countTokens());
if (CIDentry.countTokens() == 2) {
// flag if multiple values
// boolean multiple_values = false;
// if (line.indexOf('[') != -1)
// multiple_values = true;
// first 2 values define start and end
begin = Integer.parseInt(CIDentry.nextToken(), 16);
end = Integer.parseInt(CIDentry.nextToken());
// entry = Integer.parseInt(CIDentry.nextToken(), 16);
// put into array
// for (int i = begin; i < end + 1; i++) {
// if (multiple_values == true) {
// put either single values or range
// entry =Integer.parseInt(CIDentry.nextToken(), 16);
// CMAP[i]= String.valueOf((char) entry);
// } else {
this.glyphs.CMAP_Translate[begin] = end;
// entry++;
// }
// }
}
else {}
}
catch (Exception ef) {
ef.getStackTrace();
}
}
if (line.contains("begincidrange")) inDefinition = true;
else
if (line.contains("begincidchar")) inMap = true;
}
}
/**
* convert value read from TJ operand into correct glyph
* Also check to see if mapped onto unicode value
*/
private String getStandardGlyphValue(int char_int) {
// get possible unicode values
String unicode_char = getUnicodeMapping(char_int);
// handle if unicode
if (unicode_char != null) // & (mapped_char==null))
return unicode_char;
// not unicode so get mapped char
String return_value = "", mapped_char;
// get font encoding
int font_encoding = getFontEncoding(true);
mapped_char = getMappedChar(char_int, true);
// handle if differences first then standard mappings
if (mapped_char != null) { // convert name into character
// First check if the char has been mapped specifically for this
String char_mapping = StandardFonts.getUnicodeName(this.fontEnc + mapped_char);
if (char_mapping != null) return_value = char_mapping;
else {
char_mapping = StandardFonts.getUnicodeName(mapped_char);
if (char_mapping != null) return_value = char_mapping;
else {
if (mapped_char.length() == 1) {
return_value = mapped_char;
}
else
if (mapped_char.length() > 1) {
char c = mapped_char.charAt(0);
char c2 = mapped_char.charAt(1);
if (c == 'B' || c == 'C' || c == 'c' || c == 'G') {
mapped_char = mapped_char.substring(1);
try {
int val = (this.isHex) ? Integer.valueOf(mapped_char, 16) : Integer.parseInt(mapped_char);
return_value = String.valueOf((char) val);
}
catch (Exception e) {
return_value = "";
}
}
else return_value = "";
// allow for hex number
boolean isHex = ((c >= 48 && c <= 57) || (c >= 97 && c <= 102) || (c >= 65 && c <= 70))
&& ((c2 >= 48 && c2 <= 57) || (c2 >= 97 && c2 <= 102) || (c2 >= 65 && c2 <= 70));
if (return_value.length() == 0 && this.fontTypes == StandardFonts.TYPE3 && mapped_char.length() == 2 && isHex) {
return_value = String.valueOf((char) Integer.parseInt(mapped_char, 16));
}
// handle some odd mappings in Type3 and other cases
if (return_value.length() == 0) {
if (this.fontTypes == StandardFonts.TYPE3) // && !StandardFonts.isValidGlyphName(char_mapping))
return_value = String.valueOf((char) char_int);
else
if (this.diffTable != null && this.diffTable[char_int] != null && this.fontEnc == StandardFonts.WIN) { // hack for
// odd
// file
return_value = this.diffTable[char_int];
if (return_value.indexOf('_') != -1) return_value = return_value.replaceAll("_", "");
}
}
}
else return_value = "";
}
}
}
else
if (font_encoding > -1) // handle encoding
return_value = StandardFonts.getEncodedChar(font_encoding, char_int);
return return_value;
}
/** set the font being used or try to approximate */
public final Font getJavaFont(int size) {
int style = Font.PLAIN;
boolean isJavaFontInstalled = false;
String weight = null, mappedName = null, font_family_name = this.glyphs.fontName;
String testFont = font_family_name;
if (font_family_name != null) testFont = font_family_name.toLowerCase();
// System.out.print(testFont);
if (testFont.equals("arialmt")) {
testFont = "arial";
font_family_name = testFont;
}
else
if (testFont.equals("arial-boldmt")) {
testFont = "arial Bold";
font_family_name = testFont;
}
// System.out.print(testFont+" "+font_family_name);
// pick up any weight in type 3 font or - standard font mapped to Java
// int pointer = font_family_name.indexOf(",");
// if ((pointer == -1))//&&(StandardFonts.javaFontList.get(font_family_name)!=null))
// pointer = font_family_name.indexOf("-");
// if (pointer != -1) {
//
// //see if present with ,
// mappedName=(String) FontMappings.fontSubstitutionAliasTable.get(testFont);
//
// weight =testFont.substring(pointer + 1, testFont.length());
//
// if (weight.indexOf("bold") != -1)
// style = Font.BOLD;
// else if (weight.indexOf("roman") != -1)
// style = Font.ROMAN_BASELINE;
//
// if (weight.indexOf("italic") != -1)
// style = style+Font.ITALIC;
// else if (weight.indexOf("oblique") != -1)
// style = style+Font.ITALIC;
//
// font_family_name = font_family_name.substring(0, pointer);
//
// }
// remap if not type 3 match
// if(mappedName==null)
// mappedName=(String) FontMappings.fontSubstitutionAliasTable.get(testFont);
if (mappedName != null) {
font_family_name = mappedName;
testFont = font_family_name.toLowerCase();
}
// see if installed
if (PdfJavaGlyphs.fontList != null) {
int count = PdfJavaGlyphs.fontList.length;
for (int i = 0; i < count; i++) {
System.out.println(PdfJavaGlyphs.fontList[i] + "<>" + testFont);
if ((PdfJavaGlyphs.fontList[i].contains(testFont))) {
isJavaFontInstalled = true;
font_family_name = PdfJavaGlyphs.fontList[i];
i = count;
}
}
}
/** approximate display if not installed */
if (isJavaFontInstalled == false) {
// try to approximate font
if (weight == null) {
// pick up any weight
String test = font_family_name.toLowerCase();
if (test.contains("heavy")) style = Font.BOLD;
else
if (test.contains("bold")) style = Font.BOLD;
else
if (test.contains("roman")) style = Font.ROMAN_BASELINE;
if (test.contains("italic")) style = style + Font.ITALIC;
else
if (test.contains("oblique")) style = style + Font.ITALIC;
}
// font_family_name = defaultFont;
}
if (isJavaFontInstalled) return new Font(font_family_name, style, size);
else {
if (LogWriter.isOutput()) LogWriter.writeLog("No match with " + this.glyphs.getBaseFontName() + ' ' + ' ' + testFont + ' ' + weight + ' '
+ style);
return null;
}
}
/**
* set the font used for default from Java fonts on system - check it is a valid font (otherwise it will default to Lucida anyway)
*/
public final void setDefaultDisplayFont(String fontName) {
this.glyphs.defaultFont = fontName;
}
/**
* Returns the java font, initializing it first if it hasn't been used before.
*/
public final Font getJavaFontX(int size) {
// allow user to totally over-ride
// passing in this allows user to reset any global variables
// set in this method as well.
// Helper is a static instance of the inteface JPedalHelper
if (PdfDecoder.Helper != null) {
Font f = PdfDecoder.Helper.getJavaFontX(this, size);
// if you want to implement JPedalHelper but not
// use this function, just return null
if (f != null) {
return f;
}
}
// noinspection MagicConstant
return new Font(this.glyphs.font_family_name, this.glyphs.style, size);
}
/**
* reset font handle
*
* public final void unsetUnscaledFont() { unscaledFont=null; }
*/
/**
* get font name as a string from ID (ie Tf /F1) and load if one of Adobe 14
*/
final public String getFontName() {
// check if one of 14 standard fonts and load if needed
StandardFonts.loadStandardFontWidth(this.glyphs.fontName);
return this.glyphs.fontName;
}
/**
* get the copyright information
*/
final public String getCopyright() {
return this.copyright;
}
/**
* get raw font name which may include +xxxxxx
*/
final public String getBaseFontName() {
return this.glyphs.getBaseFontName();
}
/**
* set raw font name which may include +xxxxxx
*/
final public void setBaseFontName(String fontName) {
this.glyphs.setBaseFontName(fontName);
}
/**
* get width of a space
*/
final public float getCurrentFontSpaceWidth() {
float width;
// allow for space mapped onto other value
int space_value = this.spaceChar;
if (space_value != -1) width = getWidth(space_value);
else width = this.possibleSpaceWidth; // use shortest width as a guess
// allow for no value
if (width == noWidth || width == 0) width = 0.2f;
return width;
}
final protected int getFontEncoding(boolean notNull) {
int result = this.fontEnc;
if (result == -1 && notNull) result = StandardFonts.STD;
return result;
}
/**
* Returns width of the specified character
* Allows for no value set
*/
final public float getWidth(int charInt) {
// if -1 return last value fetched
if (charInt == -1) return this.lastWidth;
// try embedded font first (indexed by number)
float width = noWidth;
if (this.widthTable != null && charInt != -1) width = this.widthTable[charInt];
if (width == noWidth) {
if (this.isCIDFont) {
width = this.defaultWidth;
}
else {
// try standard values which are indexed under NAME of char
String charName = getMappedChar(charInt, false);
if ((charName != null) && (charName.equals(".notdef"))) charName = StandardFonts.getUnicodeChar(getFontEncoding(true), charInt);
Float value = StandardFonts.getStandardWidth(this.glyphs.logicalfontName, charName);
// allow for remapping of base 14 with no width
if (value == null && this.rawFontName != null) {
// check loaded
StandardFonts.loadStandardFontWidth(this.rawFontName);
// try again
value = StandardFonts.getStandardWidth(this.rawFontName, charName);
}
if (value != null) width = value;
else {
if (this.missingWidth != noWidth) width = this.missingWidth * xscale;
else width = 0;
}
}
}
// cache value so we can reread
this.lastWidth = width;
return width;
}
/**
* generic CID code
*
* @throws PdfFontException
*/
public void createCIDFont(PdfObject pdfObject, PdfObject Descendent) throws PdfFontException {
this.cachedValue = new String[65536];
String CMapName = null;
/** read encoding values */
PdfObject Encoding = pdfObject.getDictionary(PdfDictionary.Encoding);
if (Encoding != null) {
CMapName = handleCIDEncoding(Encoding, pdfObject);
}
// handle to unicode mapping
this.ToUnicode = pdfObject.getDictionary(PdfDictionary.ToUnicode);
if (this.ToUnicode != null) {
UnicodeReader uniReader = new UnicodeReader(this.currentPdfFile.readStream(this.ToUnicode, true, true, false, false, false,
this.ToUnicode.getCacheName(this.currentPdfFile.getObjectReader())));
this.unicodeMappings = uniReader.readUnicode();
this.hasDoubleBytes = uniReader.hasDoubleByteValues();
}
/** read widths */
// @speed may need optimising - done as string for moment
String widths = Descendent.getName(PdfDictionary.W);
// allow for vertical
String verticalWidths = Descendent.getName(PdfDictionary.W2);
if (verticalWidths != null) {
widths = verticalWidths;
}
if (widths != null) setCIDFontWidths(widths);
/** set default width */
int Width = Descendent.getInt(PdfDictionary.DW);
if (Width >= 0) this.defaultWidth = (Width) / 1000f;
// it looks like in this case it uses average of values
// but not enough data
if (this.handleOddSapFontMapping) {
this.defaultWidth = .5f;
}
/** set CIDtoGIDMap */
PdfObject CIDToGID = Descendent.getDictionary(PdfDictionary.CIDToGIDMap);
if (CIDToGID != null) {
byte[] stream = this.currentPdfFile.readStream(CIDToGID, true, true, false, false, false, null);
if (stream != null) {
int j = 0, count = stream.length;
this.CIDToGIDMap = new int[count / 2];
for (int i = 0; i < count; i = i + 2) {
this.CIDToGIDMap[j] = (((stream[i] & 255) << 8) + (stream[i + 1] & 255));
j++;
}
this.glyphs.setGIDtoCID(this.CIDToGIDMap);
}
else { // must be identity
// only set if not also a /value
if (CIDToGID.getParameterConstant(PdfDictionary.CIDToGIDMap) == PdfDictionary.Unknown) CMapName = handleCIDEncoding(new FontObject(
PdfDictionary.Identity_H), null);
}
}
// code is unfinished by MArk - I was originally going to map onto font in
// cid.jar but now think that is wrong
//
// Needs researching and doing properly
String ordering = null;
PdfObject CIDSystemInfo = Descendent.getDictionary(PdfDictionary.CIDSystemInfo);
if (CIDSystemInfo != null) ordering = CIDSystemInfo.getTextStreamValue(PdfDictionary.Ordering);
if (ordering != null) {
if (CIDToGID == null && ordering.contains("Identity")) {
}
else
if (ordering.contains("Japan")) {
// char[] c=new char[]{12498,12521,12462,12494,35282,12468,32,80,114,111,32,87,54};
//
// substituteFontName=new String(c);
// substituteFontFile="/Library/Fonts/"+substituteFontName+".otf";
//
// substituteFontFile="/Users/markee/Library/Fonts/MS Mincho.ttf";
// System.out.println(substituteFontFile);
this.TTstreamisCID = false;
// System.err.println("Unsupported font encoding "+ordering);
}
else
if (ordering.contains("Korean")) {
// System.err.println("Unsupported font encoding "+ordering);
}
else
if (ordering.contains("Chinese")) {
// System.err.println("Chinese "+ordering);
}
else
if (ordering.equals("Identity") && (CMapName == null || CMapName.contains("Ident"))) {
this.glyphs.setIsIdentity(true);
}
if (this.substituteFontFile != null && LogWriter.isOutput()) LogWriter.writeLog("Using font " + this.substituteFontFile + " for "
+ ordering);
}
/** set other values */
if (Descendent != null) {
PdfObject FontDescriptor = Descendent.getDictionary(PdfDictionary.FontDescriptor);
/** read other info */
if (FontDescriptor != null) {
setBoundsAndMatrix(FontDescriptor);
setName(FontDescriptor, this.fontID);
}
}
}
final protected void selectDefaultFont() {
/**
* load fonts for specific encoding*
*
* //get list of fonts and see if installed String[] fontList
* =GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
* System.out.println(substituteFontFile+" "+this.substituteFontName); Hiragino Kaku Gothic Pro Hiragino Kaku Gothic Std Hiragino Maru Gothic
* Pro Hiragino Mincho Pro
*
* defaultFont="Hiragino Mincho Pro";
*
* int count = fontList.length; for (int i = 0; i < count; i++) { System.out.println(fontList[i]); //if (fontList[i].equals(font_family_name))
* { // isFontInstalled = true; // i = count; //} }
*/
}
/** read in width values */
public void readWidths(PdfObject pdfObject, boolean setSpace) throws Exception {
// place font data in fonts array
// variable to get shortest width as guess for space
float shortestWidth = 0;
int count = 0;
// read first,last char, widths and put last into array for fast access
float[] floatWidthValues = pdfObject.getFloatArray(PdfDictionary.Widths);
if (floatWidthValues != null) {
this.widthTable = new float[this.maxCharCount];
// set all values to noWidth so I can spot ones with no value
for (int ii = 0; ii < this.maxCharCount; ii++)
this.widthTable[ii] = noWidth;
int firstCharNumber = pdfObject.getInt(PdfDictionary.FirstChar);
int lastCharNumber = pdfObject.getInt(PdfDictionary.LastChar);
// scaling factor to convert type 3 to 1000 spacing
float ratio = (float) (1f / this.FontMatrix[0]);
if (ratio < 0) ratio = -ratio;
float nextValue, widthValue;
int j = 0, widthCount = floatWidthValues.length;
for (int i = firstCharNumber; i < lastCharNumber + 1; i++) {
if (j < widthCount) {
nextValue = floatWidthValues[j];
if (this.fontTypes == StandardFonts.TYPE3) // convert to 1000 scale unit
widthValue = nextValue / ratio;
else widthValue = nextValue * xscale;
// track shortest width
if (widthValue > 0) {
shortestWidth = shortestWidth + widthValue;
count++;
}
this.widthTable[i] = widthValue;
}
else this.widthTable[i] = 0;
j++;
}
}
// save guess for space as half average char
if (setSpace && count > 0) this.possibleSpaceWidth = shortestWidth / (2 * count);
}
/** read in a font and its details from the pdf file */
public void createFont(PdfObject pdfObject, String fontID, boolean renderPage, ObjectStore objectStore, Map substitutedFonts) throws Exception {
// generic setup
init(fontID, renderPage);
/**
* get FontDescriptor object - if present contains metrics on glyphs
*/
PdfObject pdfFontDescriptor = pdfObject.getDictionary(PdfDictionary.FontDescriptor);
setName(pdfObject, fontID);
setEncoding(pdfObject, pdfFontDescriptor);
}
protected void setName(PdfObject pdfObject, String fontID) {
/**
* get name of font
*/
// Get fontName
String baseFontName = pdfObject.getName(PdfDictionary.BaseFont);
if (baseFontName == null) baseFontName = pdfObject.getName(PdfDictionary.FontName);
if (baseFontName == null) baseFontName = this.fontID;
// if(PdfStreamDecoder.runningStoryPad) //remove spaces and unwanted chars
if (baseFontName.contains("#20")) baseFontName = cleanupFontName(baseFontName);
// System.out.println("baseFontName="+baseFontName);
this.glyphs.setBaseFontName(baseFontName);
/**
* get name less any suffix (needs abcdef+ removed from start)
**/
String truncatedName = pdfObject.getStringValue(PdfDictionary.BaseFont, PdfDictionary.REMOVEPOSTSCRIPTPREFIX);
if (truncatedName == null) truncatedName = pdfObject.getStringValue(PdfDictionary.FontName, PdfDictionary.REMOVEPOSTSCRIPTPREFIX);
if (truncatedName == null) truncatedName = this.fontID;
if (truncatedName.contains("#20") || truncatedName.contains("#2D")) truncatedName = cleanupFontName(truncatedName);
// if(PdfStreamDecoder.runningStoryPad) //remove spaces and unwanted chars
// truncatedName= cleanupFontName(truncatedName);
this.glyphs.fontName = truncatedName;
if (truncatedName.equals("Arial-BoldMT")) {
this.glyphs.logicalfontName = "Arial,Bold";
StandardFonts.loadStandardFontWidth(this.glyphs.logicalfontName);
}
else
if (truncatedName.equals("ArialMT")) {
this.glyphs.logicalfontName = "Arial";
StandardFonts.loadStandardFontWidth(this.glyphs.logicalfontName);
}
else this.glyphs.logicalfontName = truncatedName;
}
/**
* used by PDF2HTML to ensure name unique
*
* @param newName
*/
public void resetNameForHTML(String newName) {
this.glyphs.fontName = newName;
this.glyphs.baseFontName = newName;
}
protected void setEncoding(PdfObject pdfObject, PdfObject pdfFontDescriptor) {
// handle to unicode mapping
PdfObject ToUnicode = pdfObject.getDictionary(PdfDictionary.ToUnicode);
if (ToUnicode != null) this.unicodeMappings = new UnicodeReader(this.currentPdfFile.readStream(ToUnicode, true, true, false, false, false,
ToUnicode.getCacheName(this.currentPdfFile.getObjectReader()))).readUnicode();
// handle encoding
PdfObject Encoding = pdfObject.getDictionary(PdfDictionary.Encoding);
if (Encoding != null) handleFontEncoding(pdfObject, Encoding);
else handleNoEncoding(0, pdfObject);
if (pdfFontDescriptor != null) {
int fontFlag = 0;
if (pdfFontDescriptor != null) fontFlag = pdfFontDescriptor.getInt(PdfDictionary.Flags);
// reset to defaults
this.glyphs.remapFont = false;
int flag = fontFlag;
if ((flag & 4) == 4) this.glyphs.remapFont = true;
// set missingWidth
this.missingWidth = pdfFontDescriptor.getInt(PdfDictionary.MissingWidth);
}
}
protected void setBoundsAndMatrix(PdfObject pdfFontDescriptor) {
/**
* get any dimensions if present
*/
if (pdfFontDescriptor != null) {
double[] newFontmatrix = pdfFontDescriptor.getDoubleArray(PdfDictionary.FontMatrix);
if (newFontmatrix != null) this.FontMatrix = newFontmatrix;
float[] newFontBBox = pdfFontDescriptor.getFloatArray(PdfDictionary.FontBBox);
if (newFontBBox != null) this.FontBBox = newFontBBox;
// set ascent and descent
float value = pdfFontDescriptor.getFloatNumber(PdfDictionary.Ascent);
if (value != 0) this.ascent = value;
value = pdfFontDescriptor.getFloatNumber(PdfDictionary.Descent);
if (value != 0) this.descent = value;
}
}
protected void init(String fontID, boolean renderPage) {
if (renderPage && PdfJavaGlyphs.fontList == null) {
// synchronized (this.getClass()) {
// Recheck
if (renderPage && PdfJavaGlyphs.fontList == null) {
// Make sure lowercase
String[] fontList = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (int i = 0; i < fontList.length; i++) {
fontList[i] = fontList[i].toLowerCase();
}
PdfJavaGlyphs.fontList = fontList;
}
// }
}
this.fontID = fontID;
this.renderPage = renderPage;
}
private int handleNoEncoding(int encValue, PdfObject pdfObject) {
int enc = pdfObject.getGeneralType(PdfDictionary.Encoding);
if (enc == StandardFonts.ZAPF) {
putFontEncoding(StandardFonts.ZAPF);
this.glyphs.defaultFont = "Zapf Dingbats"; // replace with single default
StandardFonts.checkLoaded(StandardFonts.ZAPF);
encValue = StandardFonts.ZAPF;
}
else
if (enc == StandardFonts.SYMBOL) {
putFontEncoding(StandardFonts.SYMBOL);
encValue = StandardFonts.SYMBOL;
}
else putFontEncoding(StandardFonts.STD); // default to standard
this.hasEncoding = false;
return encValue;
}
// /////////////////////////////////////////////////////////////////////
/**
* handle font encoding and store information
*/
private void handleFontEncoding(PdfObject pdfObject, PdfObject Encoding) {
int subType = pdfObject.getParameterConstant(PdfDictionary.Subtype);
int encValue = getFontEncoding(false);
if (encValue == -1) {
if (subType == StandardFonts.TRUETYPE) encValue = StandardFonts.MAC;
else encValue = StandardFonts.STD;
}
/**
* handle differences from main encoding
*/
PdfArrayIterator Diffs = Encoding.getMixedArray(PdfDictionary.Differences);
if (Diffs != null && Diffs.getTokenCount() > 0) {
this.glyphs.setIsSubsetted(true);
// needed to workout if values hex of base10
// as we have examples with both
// guess if hex or base10 by looking for numbers
// if it has a number it must be base10
byte[][] rawData = null;
if (Encoding != null) rawData = Encoding.getByteArray(PdfDictionary.Differences);
if (rawData != null) {
this.containsHexNumbers = true;
this.allNumbers = true;
for (byte[] aRawData : rawData) {
if (aRawData != null && aRawData[0] == '/') {
int length = aRawData.length;
byte[] data = aRawData;
char c, charCount = 0;
if (length == 3 && this.containsHexNumbers) {
for (int jj = 1; jj < 3; jj++) {
c = (char) data[jj];
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) charCount++;
}
}
if (charCount != 2) {
this.containsHexNumbers = false;
// System.out.println("Failed on="+new String(data)+"<");
// ii=rawData.length;
}
if (this.allNumbers) {
if (length < 4) {
for (int jj = 2; jj < length; jj++) {
c = (char) data[jj];
if ((c >= '0' && c <= '9')) {}
else {
this.allNumbers = false;
jj = length;
}
}
}
}
// exit if poss
// if(!containsHexNumbers){
// ii=rawData.length;
// }
/**/
}
}
}
int pointer = 0, type;
while (Diffs.hasMoreTokens()) {
type = Diffs.getNextValueType();
if (type == PdfArrayIterator.TYPE_KEY_INTEGER) {
pointer = Diffs.getNextValueAsInteger();
}
else {
if (type == PdfArrayIterator.TYPE_VALUE_INTEGER) {
if (this.diffCharTable == null) this.diffCharTable = new int[this.maxCharCount];
// save so we can rempa glyph to get correct value for embedded font
this.diffCharTable[pointer] = Diffs.getNextValueAsInteger(false);
}
putMappedChar(pointer, Diffs.getNextValueAsFontChar(pointer, this.containsHexNumbers, this.allNumbers));
pointer++;
}
// allow for spurious values added which should not be there
if (pointer == 256) break;
}
// get flag
this.isHex = Diffs.hasHexChars();
// pick up space
int spaceChar = Diffs.getSpaceChar();
if (spaceChar != -1) this.spaceChar = spaceChar;
}
/**
* setup Encoding
*/
int EncodingType = PdfDictionary.Unknown;
if (Encoding != null) {
this.hasEncoding = true;
// see if general value first ie /WinAnsiEncoding
int newEncodingType = Encoding.getGeneralType(PdfDictionary.Encoding);
// check object for value
if (newEncodingType == PdfDictionary.Unknown) {
if (getBaseFontName().equals("ZapfDingbats")) newEncodingType = StandardFonts.ZAPF;
else newEncodingType = Encoding.getParameterConstant(PdfDictionary.BaseEncoding);
}
if (newEncodingType != PdfDictionary.Unknown) EncodingType = newEncodingType;
else EncodingType = handleNoEncoding(encValue, pdfObject);
}
putFontEncoding(EncodingType);
}
/**
* used by PDF2HTML5 where encoding different from index in TJ command and we need to remap via glyf name (ie sample_pdf_htmls/thoughtcorp/Simple
* Relational Contracts.pdf)
*
* @param glypName
*/
final public int getDiffChar(String glypName) {
int value = -1;
Integer newVal = (Integer) this.nonStandardMappings.get(glypName);
if (newVal != null) {
value = newVal;
}
return value;
}
/** Insert a new mapped char in the name mapping table */
final protected void putMappedChar(int charInt, String mappedChar) {
if (this.diffTable == null) {
this.diffTable = new String[this.maxCharCount];
this.diffLookup = new HashMap();
}
if (charInt > 255 && this.maxCharCount == 256) { // hack for odd file
//System.err.println(charInt+" mappedChar="+mappedChar+"<");
// if(1==1)
// throw new RuntimeException("xxx");
}
else
if (this.diffTable[charInt] == null && mappedChar != null && !mappedChar.startsWith("glyph")) {
this.diffTable[charInt] = mappedChar;
this.diffLookup.put(mappedChar, charInt);
}
}
/**
* @param charInt
* @return char mapped onto value in Differences or null
*/
public String getDiffMapping(int charInt) {
if (this.diffTable == null) return null;
else return this.diffTable[charInt];
}
/** Returns the char glyph corresponding to the specified code for the specified font. */
public final String getMappedChar(int charInt, boolean remap) {
String result = null;
// check differences
if (this.diffTable != null) result = this.diffTable[charInt];
if ((remap) && (result != null) && (result.equals(".notdef"))) result = " ";
// check standard encoding
if (result == null && charInt < 335) result = StandardFonts.getUnicodeChar(getFontEncoding(true), charInt);
// all unused win values over 40 map to bullet
if (result == null && charInt > 40 && getFontEncoding(true) == StandardFonts.WIN) {
if (charInt == 173) result = "hyphen";
else result = "bullet";
}
// check embedded stream as not in baseFont encoding
if (this.isFontEmbedded && result == null) {
// diffs from embedded 1C file
if (this.diffs != null) result = this.diffs[charInt];
// Embedded encoding (which can be different from the encoding!)
if (result == null && charInt < 335) result = StandardFonts.getUnicodeChar(this.embeddedEnc, charInt);
}
return result;
}
public final String getEmbeddedChar(int charInt) {
String embeddedResult = null;
// check embedded stream as not in baseFont encoding
if (this.isFontEmbedded) {
// diffs from embedded 1C file
if (this.diffs != null) embeddedResult = this.diffs[charInt];
// Embedded encoding (which can be different from the encoding!)
if ((embeddedResult == null) && charInt < 256) embeddedResult = StandardFonts.getUnicodeChar(this.embeddedEnc, charInt);
}
return embeddedResult;
}
/**
* gets type of font (ie 3 ) so we can call type specific code.
*
* @return int of type
*/
final public int getFontType() {
return this.fontTypes;
}
/**
* name of font used to display
*/
public String getSubstituteFont() {
return this.substituteFontFile;
}
/**
* test if there is a valid value
*/
public boolean isValidCodeRange(int rawInt) {
if (this.CMAP == null) return false;
else {
// System.out.println(CMAP[rawInt]+"<<"+rawInt);
return (this.CMAP[rawInt] != null);
}
}
/** used in generic renderer */
public float getGlyphWidth(String charGlyph, int rawInt, String displayValue) {
if (this.fontTypes == StandardFonts.TRUETYPE) {
return this.glyphs.getTTWidth(charGlyph, rawInt, displayValue, false);
}
else {
return 0;
}
}
/** set subtype (only used by generic font */
public void setSubtype(int fontType) {
this.fontTypes = fontType;
}
/** used by JPedal internally for font substitution */
public void setSubstituted(boolean value) {
this.isFontSubstituted = value;
}
public PdfJavaGlyphs getGlyphData() {
// glyphs.setHasWidths(this.hasWidths());
this.glyphs.setHasWidths(true);
return this.glyphs;
}
public Font setFont(String font, int textSize) {
return this.glyphs.setFont(font, textSize); // To change body of created methods use File | Settings | File Templates.
}
public boolean is1C() {
return this.glyphs.is1C(); // To change body of created methods use File | Settings | File Templates.
}
public boolean isFontSubsetted() {
return this.glyphs.isSubsetted;
}
public void setValuesForGlyph(int rawInt, String charGlyph, String displayValue, String embeddedChar) {
this.glyphs.setValuesForGlyph(rawInt, charGlyph, displayValue, embeddedChar);
}
/**
* remove unwanted chars from string name
*/
private static String cleanupFontName(String baseFontName) {
// baseFontName=baseFontName.toLowerCase();
int length = baseFontName.length();
StringBuilder cleanedName = new StringBuilder(length);
char c;
for (int aa = 0; aa < length; aa++) {
c = baseFontName.charAt(aa);
if (c == ' ' || c == '-') {
}
else
if (c == '#' && baseFontName.charAt(aa + 1) == '2' && (baseFontName.charAt(aa + 2) == '0' || baseFontName.charAt(aa + 2) == 'D')) {
// add in the hyphen
if (baseFontName.charAt(aa + 2) == 'D') cleanedName.append('-');
aa = aa + 2;
}
else cleanedName.append(c);
}
// if(baseFontName.indexOf("#20")!=-1)
// System.out.println(baseFontName+"<>"+cleanedName.toString());
return cleanedName.toString();
}
public int getItalicAngle() {
return this.italicAngle;
}
/**
* @return bounding box to highlight
*/
public Rectangle getBoundingBox() {
if (this.BBox == null) {
// if one of standard fonts, use value from afm file
float[] standardBB = StandardFonts.getFontBounds(getFontName());
if (standardBB == null) {
if (!this.isFontEmbedded) // use default as we are displaying in Lucida
this.BBox = new Rectangle(0, 0, 1000, 1000);
else this.BBox = new Rectangle((int) (this.FontBBox[0]), (int) (this.FontBBox[1]), (int) (this.FontBBox[2] - this.FontBBox[0]),
(int) (this.FontBBox[3] - this.FontBBox[1]));
}
else this.BBox = new Rectangle((int) (standardBB[0]), (int) (standardBB[1]), (int) (standardBB[2] - standardBB[0]),
(int) (standardBB[3] - standardBB[1]));
}
return this.BBox;
}
public void setRawFontName(String baseFont) {
this.rawFontName = baseFont;
}
/**
* workout spaces (if any) to add into content for a gap from user settings, space info in pdf
*/
public static String getSpaces(float currentGap, float spaceWidth, float currentThreshold) {
String space = "";
if (spaceWidth > 0) {
if ((currentGap > spaceWidth) && (currentThreshold < 1 || currentGap > spaceWidth * currentThreshold)) {
while (currentGap >= spaceWidth) {
space = ' ' + space;
currentGap = currentGap - spaceWidth;
}
}
else
if (currentGap > spaceWidth * currentThreshold) {
// ensure a gap of at least space_thresh_hold
space = space + ' ';
}
}
return space;
}
public int getDiffChar(int index) {
if (this.diffCharTable == null) return 0;
else return this.diffCharTable[index];
}
public float[] getFontBounds() {
return this.FontBBox;
}
public boolean isFontVertical() {
return this.isFontVertical;
}
/**
* @param currentWidth
*/
public void setCurrentWidth(float currentWidth) {
this.currentWidth = currentWidth;
}
/**
* width of last decoded glyf (used for HTML)
*/
public float getCurrentWidth() {
return this.currentWidth;
}
public Object getFontID() {
return this.fontID;
}
public boolean isSingleByte() {
return this.isSingleByte;
}
/**
* workaround to handle issue with some odd SAP files Please do not use.
*
*/
public boolean isBrokenFont() {
return this.handleOddSapFontMapping;
}
/**
* Used by HTML code to tell whether to use CID range remapping or not
*
* @return Whether a 'ToUnicode' dictionary is provided.
*/
public boolean hasToUnicode() {
return this.unicodeMappings != null;
}
/**
* returns width or value in widthTable (-1 if no width set) idx=-1 returns default
*/
public float getDefaultWidth(int idx) {
if (idx == -1) {
return this.defaultWidth;
}
else {
if (this.widthTable == null) {
return -1;
}
else {
return this.widthTable[idx];
}
}
}
public float getAscent() {
return this.ascent;
}
public float getDescent() {
return this.descent;
}
/**
* work out if 1 or 2 bytes for each char
*
* @param firstVal
* @param secondByte
* @param secondByteIsEscaped
* @return
*
* 0=false 1=true -1=unset
*/
public int isDoubleBytes(int firstVal, int secondByte, boolean secondByteIsEscaped) {
if (this.hasDoubleBytes) {
return 1;
}
else
if (this.isFirstScan) { // don't bother with test if we have figured it out already
if ((firstVal == secondByte && firstVal > 0) || (secondByte == 41 && !secondByteIsEscaped)
|| (getMappedChar(firstVal, true) != null && getMappedChar(secondByte, true) != null)) {
this.isDouble = 0;
}
else {
this.isDouble = 1;
}
this.isFirstScan = false;
}
return this.isDouble;
}
/**
* flag to show if double (1), single (0) or unset (-1)
*
*/
public int isDoubleBytes() {
return this.isDouble;
}
public PdfObject getToUnicode() {
return this.ToUnicode;
}
public int[] getCIDToGIDMap() {
return this.CIDToGIDMap;
}
public String[] getCMAP() {
return this.CMAP;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PdfFont [");
if (this.ToUnicode != null) {
builder.append("ToUnicode=");
builder.append(this.ToUnicode);
builder.append(", ");
}
if (this.javaFont != null) {
builder.append("javaFont=");
builder.append(this.javaFont);
builder.append(", ");
}
if (this.BBox != null) {
builder.append("BBox=");
builder.append(this.BBox);
builder.append(", ");
}
if (this.CMapName != null) {
builder.append("CMapName=");
builder.append(this.CMapName);
builder.append(", ");
}
builder.append("handleOddSapFontMapping=");
builder.append(this.handleOddSapFontMapping);
builder.append(", isFirstScan=");
builder.append(this.isFirstScan);
builder.append(", isDouble=");
builder.append(this.isDouble);
builder.append(", containsHexNumbers=");
builder.append(this.containsHexNumbers);
builder.append(", allNumbers=");
builder.append(this.allNumbers);
builder.append(", ");
if (this.embeddedFontName != null) {
builder.append("embeddedFontName=");
builder.append(this.embeddedFontName);
builder.append(", ");
}
if (this.embeddedFamilyName != null) {
builder.append("embeddedFamilyName=");
builder.append(this.embeddedFamilyName);
builder.append(", ");
}
if (this.copyright != null) {
builder.append("copyright=");
builder.append(this.copyright);
builder.append(", ");
}
builder.append("missingWidth=");
builder.append(this.missingWidth);
builder.append(", isSingleByte=");
builder.append(this.isSingleByte);
builder.append(", isFontVertical=");
builder.append(this.isFontVertical);
builder.append(", lastWidth=");
builder.append(this.lastWidth);
builder.append(", ");
if (this.glyphs != null) {
builder.append("glyphs=");
builder.append(this.glyphs);
builder.append(", ");
}
if (this.cachedValue != null) {
builder.append("cachedValue=");
builder.append(Arrays.toString(this.cachedValue));
builder.append(", ");
}
if (this.rawFontName != null) {
builder.append("rawFontName=");
builder.append(this.rawFontName);
builder.append(", ");
}
builder.append("currentWidth=");
builder.append(this.currentWidth);
builder.append(", ");
if (this.nonStandardMappings != null) {
builder.append("nonStandardMappings=");
builder.append(this.nonStandardMappings);
builder.append(", ");
}
builder.append("hasDoubleBytes=");
builder.append(this.hasDoubleBytes);
builder.append(", ");
if (this.substituteFont != null) {
builder.append("substituteFont=");
builder.append(this.substituteFont);
builder.append(", ");
}
builder.append("renderPage=");
builder.append(this.renderPage);
builder.append(", embeddedEnc=");
builder.append(this.embeddedEnc);
builder.append(", ");
if (this.diffs != null) {
builder.append("diffs=");
builder.append(Arrays.toString(this.diffs));
builder.append(", ");
}
builder.append("isFontEmbedded=");
builder.append(this.isFontEmbedded);
builder.append(", TTstreamisCID=");
builder.append(this.TTstreamisCID);
builder.append(", ");
if (this.fontID != null) {
builder.append("fontID=");
builder.append(this.fontID);
builder.append(", ");
}
builder.append("maxCharCount=");
builder.append(this.maxCharCount);
builder.append(", hasEncoding=");
builder.append(this.hasEncoding);
builder.append(", fontTypes=");
builder.append(this.fontTypes);
builder.append(", ");
if (this.substituteFontFile != null) {
builder.append("substituteFontFile=");
builder.append(this.substituteFontFile);
builder.append(", ");
}
builder.append("spaceChar=");
builder.append(this.spaceChar);
builder.append(", ");
if (this.diffTable != null) {
builder.append("diffTable=");
builder.append(Arrays.toString(this.diffTable));
builder.append(", ");
}
if (this.diffCharTable != null) {
builder.append("diffCharTable=");
builder.append(Arrays.toString(this.diffCharTable));
builder.append(", ");
}
if (this.diffLookup != null) {
builder.append("diffLookup=");
builder.append(this.diffLookup);
builder.append(", ");
}
if (this.widthTable != null) {
builder.append("widthTable=");
builder.append(Arrays.toString(this.widthTable));
builder.append(", ");
}
builder.append("possibleSpaceWidth=");
builder.append(this.possibleSpaceWidth);
builder.append(", ");
if (this.currentPdfFile != null) {
builder.append("currentPdfFile=");
builder.append(this.currentPdfFile);
builder.append(", ");
}
if (this.loader != null) {
builder.append("loader=");
builder.append(this.loader);
builder.append(", ");
}
if (this.FontMatrix != null) {
builder.append("FontMatrix=");
builder.append(Arrays.toString(this.FontMatrix));
builder.append(", ");
}
if (this.FontBBox != null) {
builder.append("FontBBox=");
builder.append(Arrays.toString(this.FontBBox));
builder.append(", ");
}
builder.append("ascent=");
builder.append(this.ascent);
builder.append(", descent=");
builder.append(this.descent);
builder.append(", isHex=");
builder.append(this.isHex);
builder.append(", ");
if (this.unicodeMappings != null) {
builder.append("unicodeMappings=");
builder.append(Arrays.toString(this.unicodeMappings));
builder.append(", ");
}
builder.append("fontEnc=");
builder.append(this.fontEnc);
builder.append(", isCIDFont=");
builder.append(this.isCIDFont);
builder.append(", ");
if (this.CMAP != null) {
builder.append("CMAP=");
builder.append(Arrays.toString(this.CMAP));
builder.append(", ");
}
if (this.CIDfontEncoding != null) {
builder.append("CIDfontEncoding=");
builder.append(this.CIDfontEncoding);
builder.append(", ");
}
builder.append("defaultWidth=");
builder.append(this.defaultWidth);
builder.append(", isFontSubstituted=");
builder.append(this.isFontSubstituted);
builder.append(", italicAngle=");
builder.append(this.italicAngle);
builder.append(", hasMatrixSet=");
builder.append(this.hasMatrixSet);
builder.append(", hasFBoxSet=");
builder.append(this.hasFBoxSet);
builder.append(", ");
if (this.stream != null) {
builder.append("stream=");
builder.append(Arrays.toString(this.stream));
builder.append(", ");
}
if (this.CIDToGIDMap != null) {
builder.append("CIDToGIDMap=");
builder.append(Arrays.toString(this.CIDToGIDMap));
}
builder.append("]");
return builder.toString();
}
}