You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2013/08/11 12:58:20 UTC
svn commit: r1512900 [2/2] - in /pdfbox/trunk:
fontbox/src/main/java/org/apache/fontbox/cff/
pdfbox/src/main/java/org/apache/pdfbox/encoding/
pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/
pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/ pdfbo...
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java?rev=1512900&r1=1512899&r2=1512900&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java Sun Aug 11 10:58:19 2013
@@ -17,57 +17,45 @@
package org.apache.pdfbox.pdmodel.font;
-import java.awt.Font;
-import java.awt.FontFormatException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Iterator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
import org.apache.fontbox.afm.AFMParser;
import org.apache.fontbox.afm.FontMetric;
import org.apache.fontbox.cff.AFMFormatter;
-import org.apache.fontbox.cff.charset.CFFCharset;
-import org.apache.fontbox.cff.encoding.CFFEncoding;
import org.apache.fontbox.cff.CFFFont;
import org.apache.fontbox.cff.CFFParser;
-import org.apache.fontbox.cff.Type1FontFormatter;
import org.apache.fontbox.util.BoundingBox;
-
import org.apache.pdfbox.cos.COSArray;
-import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
-import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.encoding.Encoding;
-import org.apache.pdfbox.encoding.EncodingManager;
-import org.apache.pdfbox.exceptions.WrappedIOException;
import org.apache.pdfbox.pdmodel.common.PDMatrix;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
/**
* This class represents a CFF/Type2 Font (aka Type1C Font).
+ *
* @author Villu Ruusmann
- * @version $Revision: 10.0$
+ *
*/
public class PDType1CFont extends PDSimpleFont
{
private CFFFont cffFont = null;
+ private String fontname = null;
+
private Map<Integer, String> codeToName = new HashMap<Integer, String>();
private Map<Integer, String> codeToCharacter = new HashMap<Integer, String>();
@@ -76,8 +64,6 @@ public class PDType1CFont extends PDSimp
private FontMetric fontMetric = null;
- private Font awtFont = null;
-
private Map<String, Float> glyphWidths = new HashMap<String, Float>();
private Map<String, Float> glyphHeights = new HashMap<String, Float>();
@@ -88,86 +74,82 @@ public class PDType1CFont extends PDSimp
private static final Log LOG = LogFactory.getLog(PDType1CFont.class);
- private static final byte[] SPACE_BYTES = {(byte)32};
+ private static final byte[] SPACE_BYTES = { (byte) 32 };
- private COSDictionary fontDict = null;
-
private Map<Integer, Integer> codeToGlyph = new HashMap<Integer, Integer>();
-
+
/**
* Constructor.
*
* @param fontDictionary the corresponding dictionary
- * @throws IOException it somethin went wrong
+ * @throws IOException it something went wrong
*/
- public PDType1CFont( COSDictionary fontDictionary ) throws IOException
+ public PDType1CFont(COSDictionary fontDictionary) throws IOException
{
- super( fontDictionary );
- fontDict = fontDictionary;
+ super(fontDictionary);
load();
}
/**
* {@inheritDoc}
*/
- public String encode( byte[] bytes, int offset, int length ) throws IOException
+ public String encode(byte[] bytes, int offset, int length) throws IOException
{
String character = getCharacter(bytes, offset, length);
- if( character == null )
+ if (character == null)
{
- LOG.debug("No character for code " + (bytes[offset] & 0xff) + " in " + this.cffFont.getName());
+ LOG.debug("No character for code " + (bytes[offset] & 0xff) + " in " + fontname);
return null;
}
return character;
}
-
+
/**
* {@inheritDoc}
*/
@Override
- public int encodeToCID( byte[] bytes, int offset, int length )
+ public int encodeToCID(byte[] bytes, int offset, int length)
{
- if (length > 2)
- {
- return -1;
- }
- int code = bytes[offset] & 0xff;
- if (length == 2)
- {
- code = code * 256 + bytes[offset+1] & 0xff;
- }
- return code;
+ if (length > 2)
+ {
+ return -1;
+ }
+ int code = bytes[offset] & 0xff;
+ if (length == 2)
+ {
+ code = code * 256 + bytes[offset + 1] & 0xff;
+ }
+ return code;
}
-
- private String getCharacter( byte[] bytes, int offset, int length )
+
+ private String getCharacter(byte[] bytes, int offset, int length)
{
int code = encodeToCID(bytes, offset, length);
- if (code == -1)
+ if (code == -1)
{
return null;
}
- return (String)this.codeToCharacter.get(code);
+ return (String) codeToCharacter.get(code);
}
/**
* {@inheritDoc}
*/
- public float getFontWidth( byte[] bytes, int offset, int length ) throws IOException
+ public float getFontWidth(byte[] bytes, int offset, int length) throws IOException
{
String name = getName(bytes, offset, length);
- if( name == null && !Arrays.equals(SPACE_BYTES, bytes) )
+ if (name == null && !Arrays.equals(SPACE_BYTES, bytes))
{
- LOG.debug("No name for code " + (bytes[offset] & 0xff) + " in " + this.cffFont.getName());
-
+ LOG.debug("No name for code " + (bytes[offset] & 0xff) + " in " + fontname);
return 0;
}
- Float width = (Float)this.glyphWidths.get(name);
- if( width == null )
+ Float width = (Float) glyphWidths.get(name);
+ if (width == null)
{
width = Float.valueOf(getFontMetric().getCharacterWidth(name));
- this.glyphWidths.put(name, width);
+ glyphWidths.put(name, width);
}
return width.floatValue();
@@ -176,70 +158,69 @@ public class PDType1CFont extends PDSimp
/**
* {@inheritDoc}
*/
- public float getFontHeight( byte[] bytes, int offset, int length ) throws IOException
+ public float getFontHeight(byte[] bytes, int offset, int length) throws IOException
{
String name = getName(bytes, offset, length);
- if( name == null )
+ if (name == null)
{
- LOG.debug("No name for code " + (bytes[offset] & 0xff) + " in " + this.cffFont.getName());
+ LOG.debug("No name for code " + (bytes[offset] & 0xff) + " in " + fontname);
return 0;
}
- Float height = (Float)this.glyphHeights.get(name);
- if( height == null )
+ float height = 0;
+ if (!glyphHeights.containsKey(name))
{
- height = Float.valueOf(getFontMetric().getCharacterHeight(name));
- this.glyphHeights.put(name, height);
+ height = getFontMetric().getCharacterHeight(name);
+ glyphHeights.put(name, height);
}
-
- return height.floatValue();
+ return height;
}
- private String getName( byte[] bytes, int offset, int length )
+ private String getName(byte[] bytes, int offset, int length)
{
if (length > 2)
{
return null;
}
-
+
int code = bytes[offset] & 0xff;
if (length == 2)
{
- code = code * 256 + bytes[offset+1] & 0xff;
+ code = code * 256 + bytes[offset + 1] & 0xff;
}
- return (String)this.codeToName.get(code);
+ return codeToName.get(code);
}
/**
* {@inheritDoc}
*/
- public float getStringWidth( String string ) throws IOException
+ public float getStringWidth(String string) throws IOException
{
float width = 0;
- for( int i = 0; i < string.length(); i++ )
+ for (int i = 0; i < string.length(); i++)
{
String character = string.substring(i, i + 1);
Integer code = getCode(character);
- if( code == null )
+ if (code == null)
{
LOG.debug("No code for character " + character);
return 0;
}
- width += getFontWidth(new byte[]{(byte)code.intValue()}, 0, 1);
+ width += getFontWidth(new byte[] { (byte) code.intValue() }, 0, 1);
}
return width;
}
- private Integer getCode( String character )
+ private Integer getCode(String character)
{
- return (Integer)this.characterToCode.get(character);
+ return characterToCode.get(character);
}
/**
@@ -248,7 +229,7 @@ public class PDType1CFont extends PDSimp
* @param code the character code
* @return the glyph index
*/
- protected Integer getGlyphIndex(int code)
+ protected Integer getGlyphIndex(int code)
{
return codeToGlyph.get(code);
}
@@ -258,12 +239,12 @@ public class PDType1CFont extends PDSimp
*/
public float getAverageFontWidth() throws IOException
{
- if( this.avgWidth == null )
+ if (avgWidth == null)
{
- this.avgWidth = Float.valueOf(getFontMetric().getAverageCharacterWidth());
+ avgWidth = getFontMetric().getAverageCharacterWidth();
}
- return this.avgWidth.floatValue();
+ return avgWidth.floatValue();
}
/**
@@ -271,12 +252,12 @@ public class PDType1CFont extends PDSimp
*/
public PDRectangle getFontBoundingBox() throws IOException
{
- if( this.fontBBox == null )
+ if (fontBBox == null)
{
- this.fontBBox = new PDRectangle(getFontMetric().getFontBBox());
+ fontBBox = new PDRectangle(getFontMetric().getFontBBox());
}
- return this.fontBBox;
+ return fontBBox;
}
/**
@@ -284,13 +265,13 @@ public class PDType1CFont extends PDSimp
*/
public PDMatrix getFontMatrix()
{
- if( fontMatrix == null )
+ if (fontMatrix == null)
{
- List<Number> numbers = (List<Number>)this.cffFont.getProperty("FontMatrix");
- if( numbers != null && numbers.size() == 6 )
+ List<Number> numbers = (List<Number>) cffFont.getProperty("FontMatrix");
+ if (numbers != null && numbers.size() == 6)
{
COSArray array = new COSArray();
- for(Number number : numbers)
+ for (Number number : numbers)
{
array.add(new COSFloat(number.floatValue()));
}
@@ -304,19 +285,7 @@ public class PDType1CFont extends PDSimp
return fontMatrix;
}
- /**
- * {@inheritDoc}
- */
- public Font getawtFont() throws IOException
- {
- if (awtFont == null)
- {
- this.awtFont = prepareAwtFont(this.cffFont);
- }
- return awtFont;
- }
-
- private FontMetric getFontMetric()
+ private FontMetric getFontMetric()
{
if (fontMetric == null)
{
@@ -342,95 +311,69 @@ public class PDType1CFont extends PDSimp
String baseFontName = getBaseFont();
if (fonts.size() > 1 && baseFontName != null)
{
- for (CFFFont font: fonts)
+ for (CFFFont font : fonts)
{
- if (baseFontName.equals(font.getName()))
+ if (baseFontName.equals(font.getName()))
{
- this.cffFont = font;
+ cffFont = font;
break;
}
}
}
- if (this.cffFont == null)
+ if (cffFont == null)
{
- this.cffFont = (CFFFont)fonts.get(0);
+ cffFont = (CFFFont) fonts.get(0);
}
+ // chache the font name
+ fontname = cffFont.getName();
- PDFEncoding pdfEncoding = new PDFEncoding();
-
- PDFCharset pdfCharset = new PDFCharset();
+ // TODO is this really needed?
+ Number defaultWidthX = (Number) this.cffFont.getProperty("defaultWidthX");
+ glyphWidths.put(null, Float.valueOf(defaultWidthX.floatValue()));
- Map<String,byte[]> charStringsDict = this.cffFont.getCharStringsDict();
- Map<String,byte[]> pdfCharStringsDict = new LinkedHashMap<String,byte[]>();
- pdfCharStringsDict.put(".notdef", charStringsDict.get(".notdef"));
-
- Map<Integer,String> codeToNameMap = new LinkedHashMap<Integer,String>();
-
- Collection<CFFFont.Mapping> mappings = this.cffFont.getMappings();
- for( Iterator<CFFFont.Mapping> it = mappings.iterator(); it.hasNext();)
+ // calculate some mappings to be used for rendering and text extraction
+ Encoding encoding = getFontEncoding();
+ Map<String, Integer> nameToCode = encoding != null ? encoding.getNameToCodeMap() : null;
+ Collection<CFFFont.Mapping> mappings = cffFont.getMappings();
+ Map<Integer, String> codeToNameMap = new LinkedHashMap<Integer, String>();
+ for (CFFFont.Mapping mapping : mappings)
{
- CFFFont.Mapping mapping = it.next();
- Integer code = Integer.valueOf(mapping.getCode());
- String name = mapping.getName();
- codeToNameMap.put(code, name);
+ codeToNameMap.put(mapping.getCode(), mapping.getName());
}
-
- Set<String> knownNames = new HashSet<String>(codeToNameMap.values());
-
- Map<Integer,String> codeToNameOverride = loadOverride();
- for( Iterator<Map.Entry<Integer, String>> it = (codeToNameOverride.entrySet()).iterator(); it.hasNext();)
+ int glyphId = 0;
+ for (CFFFont.Mapping mapping : mappings)
{
- Map.Entry<Integer, String> entry = it.next();
- Integer code = (Integer)entry.getKey();
- String name = (String)entry.getValue();
- if(knownNames.contains(name))
+ int code = mapping.getSID();
+ String name = mapping.getName();
+ String character = null;
+ if (nameToCode != null && nameToCode.containsKey(name))
{
- Iterator<Map.Entry<Integer, String>> iter = codeToNameMap.entrySet().iterator();
- while (iter.hasNext())
- {
- Map.Entry<Integer, String> existingEntry = iter.next();
- if (existingEntry.getValue().equals(name))
- {
- iter.remove();
- break;
- }
- }
- codeToNameMap.put(code, name);
+ code = nameToCode.get(name);
+ character = encoding.getCharacter(name);
}
- }
-
- int glyphIndex = 0;
- for( Iterator<Map.Entry<Integer,String>> it = (codeToNameMap.entrySet()).iterator(); it.hasNext();)
- {
- Map.Entry<Integer,String> entry = it.next();
- Integer code = (Integer)entry.getKey();
- String name = (String)entry.getValue();
- String uniName = "uni" + hexString(code.intValue(), 4);
- String character = String.valueOf((char) code.intValue());
- pdfEncoding.register(code.intValue(), code.intValue());
- pdfCharset.register(code.intValue(), uniName);
- codeToName.put(code, uniName);
+ if (character == null)
+ {
+ character = Encoding.getCharacterForName(name);
+ }
+ if (character == null)
+ {
+ name = "uni" + hexString(code, 4);
+ character = String.valueOf(Character.toChars(code));
+ }
+ codeToGlyph.put(code, glyphId++);
+ codeToName.put(code, name);
codeToCharacter.put(code, character);
characterToCode.put(character, code);
- codeToGlyph.put(code, glyphIndex++);
- pdfCharStringsDict.put(uniName, charStringsDict.get(name));
}
-
- this.cffFont.setEncoding(pdfEncoding);
- this.cffFont.setCharset(pdfCharset);
- charStringsDict.clear();
- charStringsDict.putAll(pdfCharStringsDict);
- Number defaultWidthX = (Number)this.cffFont.getProperty("defaultWidthX");
- this.glyphWidths.put(null, Float.valueOf(defaultWidthX.floatValue()));
}
private byte[] loadBytes() throws IOException
{
PDFontDescriptor fd = getFontDescriptor();
- if( fd != null && fd instanceof PDFontDescriptorDictionary)
+ if (fd != null && fd instanceof PDFontDescriptorDictionary)
{
- PDStream ff3Stream = ((PDFontDescriptorDictionary)fd).getFontFile3();
- if( ff3Stream != null )
+ PDStream ff3Stream = ((PDFontDescriptorDictionary) fd).getFontFile3();
+ if (ff3Stream != null)
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
@@ -438,10 +381,10 @@ public class PDType1CFont extends PDSimp
try
{
byte[] buf = new byte[512];
- while(true)
+ while (true)
{
int count = is.read(buf);
- if( count < 0 )
+ if (count < 0)
{
break;
}
@@ -456,117 +399,20 @@ public class PDType1CFont extends PDSimp
return os.toByteArray();
}
}
-
- throw new IOException();
+ return null;
}
- private Map<Integer,String> loadOverride() throws IOException
- {
- Map<Integer,String> result = new LinkedHashMap<Integer,String>();
- COSBase encoding = fontDict.getDictionaryObject(COSName.ENCODING);
- if( encoding instanceof COSName )
- {
- COSName name = (COSName)encoding;
- result.putAll(loadEncoding(name));
- }
- else if( encoding instanceof COSDictionary )
- {
- COSDictionary encodingDic = (COSDictionary)encoding;
- COSName baseName = (COSName)encodingDic.getDictionaryObject(COSName.BASE_ENCODING);
- if( baseName != null )
- {
- result.putAll(loadEncoding(baseName));
- }
- COSArray differences = (COSArray)encodingDic.getDictionaryObject(COSName.DIFFERENCES);
- if( differences != null )
- {
- Map<Integer, String> diffs = loadDifferences(differences);
- if (baseName == null)
- {
- result.putAll(diffs);
- }
- else
- {
- Set<String> knownNames = new HashSet<String>(result.values());
- Iterator<Map.Entry<Integer, String>> it = (diffs.entrySet()).iterator();
- while (it.hasNext())
- {
- Map.Entry<Integer, String> entry = it.next();
- Integer code = (Integer) entry.getKey();
- String name = (String) entry.getValue();
- if (knownNames.contains(name))
- {
- Iterator<Map.Entry<Integer, String>> iter = result.entrySet().iterator();
- while( iter.hasNext())
- {
- Map.Entry<Integer, String> existingEntry = iter.next();
- if (existingEntry.getValue().equals(name))
- {
- iter.remove();
- break;
- }
- }
- }
- result.put(code, name);
- }
- }
- }
- }
- return result;
- }
-
- private Map<Integer,String> loadEncoding(COSName name) throws IOException
- {
- Map<Integer,String> result = new LinkedHashMap<Integer,String>();
- Encoding encoding = EncodingManager.INSTANCE.getEncoding(name);
- for( Iterator<Map.Entry<Integer,String>> it = (encoding.getCodeToNameMap().entrySet()).iterator();
- it.hasNext();)
- {
- Map.Entry<Integer,String> entry = it.next();
- result.put(entry.getKey(), (entry.getValue()));
- }
-
- return result;
- }
-
- private Map<Integer,String> loadDifferences(COSArray differences)
- {
- Map<Integer,String> result = new LinkedHashMap<Integer,String>();
- Integer code = null;
- for( int i = 0; i < differences.size(); i++)
- {
- COSBase element = differences.get(i);
- if( element instanceof COSNumber )
- {
- COSNumber number = (COSNumber)element;
- code = Integer.valueOf(number.intValue());
- }
- else
- {
- if( element instanceof COSName )
- {
- COSName name = (COSName)element;
- result.put(code, name.getName());
- code = Integer.valueOf(code.intValue() + 1);
- }
- }
- }
- return result;
- }
-
-
- private static String hexString( int code, int length )
+ private static String hexString(int code, int length)
{
String string = Integer.toHexString(code).toUpperCase();
- while(string.length() < length)
+ while (string.length() < length)
{
string = ("0" + string);
}
-
return string;
}
- private FontMetric prepareFontMetric( CFFFont font ) throws IOException
+ private FontMetric prepareFontMetric(CFFFont font) throws IOException
{
byte[] afmBytes = AFMFormatter.format(font);
@@ -580,12 +426,9 @@ public class PDType1CFont extends PDSimp
// Replace default FontBBox value with a newly computed one
BoundingBox bounds = result.getFontBBox();
- List<Integer> numbers = Arrays.asList(
- Integer.valueOf((int)bounds.getLowerLeftX()),
- Integer.valueOf((int)bounds.getLowerLeftY()),
- Integer.valueOf((int)bounds.getUpperRightX()),
- Integer.valueOf((int)bounds.getUpperRightY())
- );
+ List<Integer> numbers = Arrays.asList(Integer.valueOf((int) bounds.getLowerLeftX()),
+ Integer.valueOf((int) bounds.getLowerLeftY()), Integer.valueOf((int) bounds.getUpperRightX()),
+ Integer.valueOf((int) bounds.getUpperRightY()));
font.addValueToTopDict("FontBBox", numbers);
return result;
@@ -596,58 +439,14 @@ public class PDType1CFont extends PDSimp
}
}
- private static Font prepareAwtFont( CFFFont font ) throws IOException
- {
- byte[] type1Bytes = Type1FontFormatter.format(font);
-
- InputStream is = new ByteArrayInputStream(type1Bytes);
- try
- {
- return Font.createFont(Font.TYPE1_FONT, is);
- }
- catch( FontFormatException ffe )
- {
- throw new WrappedIOException(ffe);
- }
- finally
- {
- is.close();
- }
- }
-
- /**
- * This class represents a PDFEncoding.
- *
- */
- private static class PDFEncoding extends CFFEncoding
- {
-
- private PDFEncoding()
- {
- }
-
- public boolean isFontSpecific()
- {
- return true;
- }
-
- }
-
/**
- * This class represents a PDFCharset.
- *
+ * Returns the raw data of the font as CFFFont.
+ *
+ * @return the cffFont
+ * @throws IOException if something went wrong
*/
- private static class PDFCharset extends CFFCharset
+ public CFFFont getCFFFont() throws IOException
{
- private PDFCharset()
- {
- }
-
- public boolean isFontSpecific()
- {
- return true;
- }
-
+ return cffFont;
}
-
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java?rev=1512900&r1=1512899&r2=1512900&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java Sun Aug 11 10:58:19 2013
@@ -16,24 +16,25 @@
*/
package org.apache.pdfbox.pdmodel.font;
-import java.awt.Font;
-import java.awt.FontFormatException;
-import java.awt.font.GlyphVector;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
-import java.lang.reflect.Field;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.afm.AFMParser;
import org.apache.fontbox.afm.FontMetric;
import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.encoding.AFMEncoding;
import org.apache.pdfbox.encoding.Encoding;
import org.apache.pdfbox.encoding.EncodingManager;
@@ -41,12 +42,13 @@ import org.apache.pdfbox.encoding.Type1E
import org.apache.pdfbox.encoding.WinAnsiEncoding;
import org.apache.pdfbox.pdmodel.common.PDMatrix;
import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.util.ResourceLoader;
/**
* This is implementation of the Type1 Font.
- *
+ *
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.11 $
+ *
*/
public class PDType1Font extends PDSimpleFont
{
@@ -60,80 +62,133 @@ public class PDType1Font extends PDSimpl
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font TIMES_ROMAN = new PDType1Font( "Times-Roman" );
+ public static final PDType1Font TIMES_ROMAN = new PDType1Font("Times-Roman");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font TIMES_BOLD = new PDType1Font( "Times-Bold" );
+ public static final PDType1Font TIMES_BOLD = new PDType1Font("Times-Bold");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font TIMES_ITALIC = new PDType1Font( "Times-Italic" );
+ public static final PDType1Font TIMES_ITALIC = new PDType1Font("Times-Italic");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font TIMES_BOLD_ITALIC = new PDType1Font( "Times-BoldItalic" );
+ public static final PDType1Font TIMES_BOLD_ITALIC = new PDType1Font("Times-BoldItalic");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font HELVETICA = new PDType1Font( "Helvetica" );
+ public static final PDType1Font HELVETICA = new PDType1Font("Helvetica");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font HELVETICA_BOLD = new PDType1Font( "Helvetica-Bold" );
+ public static final PDType1Font HELVETICA_BOLD = new PDType1Font("Helvetica-Bold");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font HELVETICA_OBLIQUE = new PDType1Font( "Helvetica-Oblique" );
+ public static final PDType1Font HELVETICA_OBLIQUE = new PDType1Font("Helvetica-Oblique");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font HELVETICA_BOLD_OBLIQUE = new PDType1Font( "Helvetica-BoldOblique" );
+ public static final PDType1Font HELVETICA_BOLD_OBLIQUE = new PDType1Font("Helvetica-BoldOblique");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font COURIER = new PDType1Font( "Courier" );
+ public static final PDType1Font COURIER = new PDType1Font("Courier");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font COURIER_BOLD = new PDType1Font( "Courier-Bold" );
+ public static final PDType1Font COURIER_BOLD = new PDType1Font("Courier-Bold");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font COURIER_OBLIQUE = new PDType1Font( "Courier-Oblique" );
+ public static final PDType1Font COURIER_OBLIQUE = new PDType1Font("Courier-Oblique");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font( "Courier-BoldOblique" );
+ public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font("Courier-BoldOblique");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font SYMBOL = new PDType1Font( "Symbol" );
+ public static final PDType1Font SYMBOL = new PDType1Font("Symbol");
/**
* Standard Base 14 Font.
*/
- public static final PDType1Font ZAPF_DINGBATS = new PDType1Font( "ZapfDingbats" );
+ public static final PDType1Font ZAPF_DINGBATS = new PDType1Font("ZapfDingbats");
private static final Map<String, PDType1Font> STANDARD_14 = new HashMap<String, PDType1Font>();
static
{
- STANDARD_14.put( TIMES_ROMAN.getBaseFont(), TIMES_ROMAN );
- STANDARD_14.put( TIMES_BOLD.getBaseFont(), TIMES_BOLD );
- STANDARD_14.put( TIMES_ITALIC.getBaseFont(), TIMES_ITALIC );
- STANDARD_14.put( TIMES_BOLD_ITALIC.getBaseFont(), TIMES_BOLD_ITALIC );
- STANDARD_14.put( HELVETICA.getBaseFont(), HELVETICA );
- STANDARD_14.put( HELVETICA_BOLD.getBaseFont(), HELVETICA_BOLD );
- STANDARD_14.put( HELVETICA_OBLIQUE.getBaseFont(), HELVETICA_OBLIQUE );
- STANDARD_14.put( HELVETICA_BOLD_OBLIQUE.getBaseFont(), HELVETICA_BOLD_OBLIQUE );
- STANDARD_14.put( COURIER.getBaseFont(), COURIER );
- STANDARD_14.put( COURIER_BOLD.getBaseFont(), COURIER_BOLD );
- STANDARD_14.put( COURIER_OBLIQUE.getBaseFont(), COURIER_OBLIQUE );
- STANDARD_14.put( COURIER_BOLD_OBLIQUE.getBaseFont(), COURIER_BOLD_OBLIQUE );
- STANDARD_14.put( SYMBOL.getBaseFont(), SYMBOL );
- STANDARD_14.put( ZAPF_DINGBATS.getBaseFont(), ZAPF_DINGBATS );
+ STANDARD_14.put(TIMES_ROMAN.getBaseFont(), TIMES_ROMAN);
+ STANDARD_14.put(TIMES_BOLD.getBaseFont(), TIMES_BOLD);
+ STANDARD_14.put(TIMES_ITALIC.getBaseFont(), TIMES_ITALIC);
+ STANDARD_14.put(TIMES_BOLD_ITALIC.getBaseFont(), TIMES_BOLD_ITALIC);
+ STANDARD_14.put(HELVETICA.getBaseFont(), HELVETICA);
+ STANDARD_14.put(HELVETICA_BOLD.getBaseFont(), HELVETICA_BOLD);
+ STANDARD_14.put(HELVETICA_OBLIQUE.getBaseFont(), HELVETICA_OBLIQUE);
+ STANDARD_14.put(HELVETICA_BOLD_OBLIQUE.getBaseFont(), HELVETICA_BOLD_OBLIQUE);
+ STANDARD_14.put(COURIER.getBaseFont(), COURIER);
+ STANDARD_14.put(COURIER_BOLD.getBaseFont(), COURIER_BOLD);
+ STANDARD_14.put(COURIER_OBLIQUE.getBaseFont(), COURIER_OBLIQUE);
+ STANDARD_14.put(COURIER_BOLD_OBLIQUE.getBaseFont(), COURIER_BOLD_OBLIQUE);
+ STANDARD_14.put(SYMBOL.getBaseFont(), SYMBOL);
+ STANDARD_14.put(ZAPF_DINGBATS.getBaseFont(), ZAPF_DINGBATS);
}
- private Font awtFont = null;
+ /**
+ * The static map of the default Adobe font metrics.
+ */
+ private static final Map<String, FontMetric> afmObjects = Collections.unmodifiableMap(getAdobeFontMetrics());
+
+ private FontMetric afm = null;
+
+ private static Map<String, FontMetric> getAdobeFontMetrics()
+ {
+ Map<String, FontMetric> metrics = new HashMap<String, FontMetric>();
+ addAdobeFontMetric(metrics, "Courier-Bold");
+ addAdobeFontMetric(metrics, "Courier-BoldOblique");
+ addAdobeFontMetric(metrics, "Courier");
+ addAdobeFontMetric(metrics, "Courier-Oblique");
+ addAdobeFontMetric(metrics, "Helvetica");
+ addAdobeFontMetric(metrics, "Helvetica-Bold");
+ addAdobeFontMetric(metrics, "Helvetica-BoldOblique");
+ addAdobeFontMetric(metrics, "Helvetica-Oblique");
+ addAdobeFontMetric(metrics, "Symbol");
+ addAdobeFontMetric(metrics, "Times-Bold");
+ addAdobeFontMetric(metrics, "Times-BoldItalic");
+ addAdobeFontMetric(metrics, "Times-Italic");
+ addAdobeFontMetric(metrics, "Times-Roman");
+ addAdobeFontMetric(metrics, "ZapfDingbats");
+ return metrics;
+ }
+
+ private static final String resourceRootAFM = "org/apache/pdfbox/resources/afm/";
+
+ private static void addAdobeFontMetric(Map<String, FontMetric> metrics, String name)
+ {
+ try
+ {
+ String resource = resourceRootAFM + name + ".afm";
+ InputStream afmStream = ResourceLoader.loadResource(resource);
+ if (afmStream != null)
+ {
+ try
+ {
+ AFMParser parser = new AFMParser(afmStream);
+ parser.parse();
+ metrics.put(name, parser.getResult());
+ }
+ finally
+ {
+ afmStream.close();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ LOG.error("Something went wrong when reading the adobe afm files", e);
+ }
+ }
/**
* Constructor.
@@ -141,31 +196,31 @@ public class PDType1Font extends PDSimpl
public PDType1Font()
{
super();
- font.setItem( COSName.SUBTYPE, COSName.TYPE1 );
+ font.setItem(COSName.SUBTYPE, COSName.TYPE1);
}
/**
* Constructor.
- *
+ *
* @param fontDictionary The font dictionary according to the PDF specification.
*/
- public PDType1Font( COSDictionary fontDictionary )
+ public PDType1Font(COSDictionary fontDictionary)
{
- super( fontDictionary );
+ super(fontDictionary);
PDFontDescriptor fd = getFontDescriptor();
if (fd != null && fd instanceof PDFontDescriptorDictionary)
{
// a Type1 font may contain a Type1C font
- PDStream fontFile3 = ((PDFontDescriptorDictionary)fd).getFontFile3();
+ PDStream fontFile3 = ((PDFontDescriptorDictionary) fd).getFontFile3();
if (fontFile3 != null)
{
- try
+ try
{
- type1CFont = new PDType1CFont( super.font );
+ type1CFont = new PDType1CFont(super.font);
}
- catch (IOException exception)
+ catch (IOException exception)
{
- LOG.info("Can't read the embedded type1C font " + fd.getFontName() );
+ LOG.info("Can't read the embedded type1C font " + fd.getFontName());
}
}
}
@@ -173,98 +228,65 @@ public class PDType1Font extends PDSimpl
/**
* Constructor.
- *
+ *
* @param baseFont The base font for this font.
*/
- public PDType1Font( String baseFont )
+ public PDType1Font(String baseFont)
{
this();
- setBaseFont( baseFont );
+ setBaseFont(baseFont);
setFontEncoding(new WinAnsiEncoding());
setEncoding(COSName.WIN_ANSI_ENCODING);
}
+ protected FontMetric getAFM()
+ {
+ if (afm == null)
+ {
+ COSBase baseFont = font.getDictionaryObject(COSName.BASE_FONT);
+ String name = null;
+ if (baseFont instanceof COSName)
+ {
+ name = ((COSName) baseFont).getName();
+ if (name.indexOf("+") > -1)
+ {
+ name = name.substring(name.indexOf("+") + 1);
+ }
+
+ }
+ else if (baseFont instanceof COSString)
+ {
+ COSString string = (COSString) baseFont;
+ name = string.getString();
+ }
+ if (name != null)
+ {
+ afm = afmObjects.get(name);
+ }
+ }
+ return afm;
+ }
+
/**
* A convenience method to get one of the standard 14 font from name.
- *
+ *
* @param name The name of the font to get.
- *
+ *
* @return The font that matches the name or null if it does not exist.
*/
- public static PDType1Font getStandardFont( String name )
+ public static PDType1Font getStandardFont(String name)
{
- return (PDType1Font)STANDARD_14.get( name );
+ return (PDType1Font) STANDARD_14.get(name);
}
/**
* This will get the names of the standard 14 fonts.
- *
+ *
* @return An array of the names of the standard 14 fonts.
*/
public static String[] getStandard14Names()
{
- return (String[])STANDARD_14.keySet().toArray( new String[14] );
- }
-
- /**
- * {@inheritDoc}
- */
- public Font getawtFont() throws IOException
- {
- if( awtFont == null )
- {
- if (type1CFont != null)
- {
- awtFont = type1CFont.getawtFont();
- }
- else
- {
- String baseFont = getBaseFont();
- PDFontDescriptor fd = getFontDescriptor();
- if (fd != null && fd instanceof PDFontDescriptorDictionary)
- {
- PDFontDescriptorDictionary fdDictionary = (PDFontDescriptorDictionary)fd;
- if( fdDictionary.getFontFile() != null )
- {
- try
- {
- // create a type1 font with the embedded data
- awtFont = Font.createFont( Font.TYPE1_FONT,
- fdDictionary.getFontFile().createInputStream() );
- }
- catch (FontFormatException e)
- {
- LOG.info("Can't read the embedded type1 font " + fd.getFontName() );
- }
- }
- if (awtFont == null)
- {
- // check if the font is part of our environment
- awtFont = FontManager.getAwtFont(fd.getFontName());
- if (awtFont == null)
- {
- LOG.info("Can't find the specified font " + fd.getFontName() );
- }
- }
- }
- else
- {
- // check if the font is part of our environment
- awtFont = FontManager.getAwtFont(baseFont);
- if (awtFont == null)
- {
- LOG.info("Can't find the specified basefont " + baseFont );
- }
- }
- }
- if (awtFont == null)
- {
- // we can't find anything, so we have to use the standard font
- awtFont = FontManager.getStandardFont();
- LOG.info("Using font "+awtFont.getName()+ " instead");
- }
- }
- return awtFont;
+ return (String[]) STANDARD_14.keySet().toArray(new String[14]);
}
/**
@@ -275,47 +297,47 @@ public class PDType1Font extends PDSimpl
{
super.determineEncoding();
Encoding fontEncoding = getFontEncoding();
- if(fontEncoding == null)
+ if (fontEncoding == null)
{
FontMetric metric = getAFM();
if (metric != null)
{
- fontEncoding = new AFMEncoding( metric );
+ fontEncoding = new AFMEncoding(metric);
}
setFontEncoding(fontEncoding);
}
getEncodingFromFont(getFontEncoding() == null);
}
-
+
/**
* Tries to get the encoding for the type1 font.
- *
+ *
*/
private void getEncodingFromFont(boolean extractEncoding)
{
// This whole section of code needs to be replaced with an actual type1 font parser!!
// Get the font program from the embedded type font.
PDFontDescriptor fontDescriptor = getFontDescriptor();
- if( fontDescriptor != null && fontDescriptor instanceof PDFontDescriptorDictionary)
+ if (fontDescriptor != null && fontDescriptor instanceof PDFontDescriptorDictionary)
{
- PDStream fontFile = ((PDFontDescriptorDictionary)fontDescriptor).getFontFile();
- if( fontFile != null )
+ PDStream fontFile = ((PDFontDescriptorDictionary) fontDescriptor).getFontFile();
+ if (fontFile != null)
{
BufferedReader in = null;
- try
+ try
{
in = new BufferedReader(new InputStreamReader(fontFile.createInputStream()));
-
+
// this section parses the font program stream searching for a /Encoding entry
// if it contains an array of values a Type1Encoding will be returned
// if it encoding contains an encoding name the corresponding Encoding will be returned
String line = "";
Type1Encoding encoding = null;
- while( (line = in.readLine()) != null)
+ while ((line = in.readLine()) != null)
{
- if (extractEncoding)
+ if (extractEncoding)
{
- if (line.startsWith("currentdict end"))
+ if (line.startsWith("currentdict end"))
{
if (encoding != null)
{
@@ -323,9 +345,9 @@ public class PDType1Font extends PDSimpl
}
break;
}
- if (line.startsWith("/Encoding"))
+ if (line.startsWith("/Encoding"))
{
- if(line.contains("array"))
+ if (line.contains("array"))
{
StringTokenizer st = new StringTokenizer(line);
// ignore the first token
@@ -341,37 +363,36 @@ public class PDType1Font extends PDSimpl
// ignore the first token
st.nextElement();
String type1Encoding = st.nextToken();
- setFontEncoding(
- EncodingManager.INSTANCE.getEncoding(
- COSName.getPDFName(type1Encoding)));
+ setFontEncoding(EncodingManager.INSTANCE.getEncoding(COSName
+ .getPDFName(type1Encoding)));
break;
}
}
- else if (line.startsWith("dup"))
+ else if (line.startsWith("dup"))
{
- StringTokenizer st = new StringTokenizer(line.replaceAll("/"," /"));
+ StringTokenizer st = new StringTokenizer(line.replaceAll("/", " /"));
// ignore the first token
st.nextElement();
try
{
int index = Integer.parseInt(st.nextToken());
String name = st.nextToken();
- if(encoding == null)
+ if (encoding == null)
{
- LOG.warn("Unable to get character encoding. " +
- "Encoding definition found without /Encoding line.");
+ LOG.warn("Unable to get character encoding. "
+ + "Encoding definition found without /Encoding line.");
}
else
{
encoding.addCharacterEncoding(index, name.replace("/", ""));
}
}
- catch(NumberFormatException exception)
+ catch (NumberFormatException exception)
{
- // there are (tex?)-some fonts containing postscript code like the following,
+ // there are (tex?)-some fonts containing postscript code like the following,
// which has to be ignored, see PDFBOX-1481
// dup dup 161 10 getinterval 0 exch putinterval ....
- LOG.debug("Malformed encoding definition ignored (line="+line+")");
+ LOG.debug("Malformed encoding definition ignored (line=" + line + ")");
}
continue;
}
@@ -384,14 +405,14 @@ public class PDType1Font extends PDSimpl
// most likely all matrix values are in the same line than the keyword
if (line.indexOf("[") > -1)
{
- String matrixValues = line.substring(line.indexOf("[")+1,line.lastIndexOf("]"));
+ String matrixValues = line.substring(line.indexOf("[") + 1, line.lastIndexOf("]"));
StringTokenizer st = new StringTokenizer(matrixValues);
COSArray array = new COSArray();
if (st.countTokens() >= 6)
{
- try
+ try
{
- for (int i=0;i<6;i++)
+ for (int i = 0; i < 6; i++)
{
COSFloat floatValue = new COSFloat(Float.parseFloat(st.nextToken()));
array.add(floatValue);
@@ -408,7 +429,7 @@ public class PDType1Font extends PDSimpl
{
// there are fonts where all values are on a separate line, see PDFBOX-1611
COSArray array = new COSArray();
- while((line = in.readLine()) != null)
+ while ((line = in.readLine()) != null)
{
if (line.startsWith("["))
{
@@ -440,7 +461,7 @@ public class PDType1Font extends PDSimpl
}
}
}
- catch(IOException exception)
+ catch (IOException exception)
{
LOG.error("Error: Could not extract the encoding from the embedded type1 font.");
}
@@ -452,7 +473,7 @@ public class PDType1Font extends PDSimpl
{
in.close();
}
- catch(IOException exception)
+ catch (IOException exception)
{
LOG.error("An error occurs while closing the stream used to read the embedded type1 font.");
}
@@ -468,7 +489,7 @@ public class PDType1Font extends PDSimpl
@Override
public String encode(byte[] c, int offset, int length) throws IOException
{
- if (type1CFont != null)
+ if (type1CFont != null && getFontEncoding() == null)
{
return type1CFont.encode(c, offset, length);
}
@@ -477,23 +498,23 @@ public class PDType1Font extends PDSimpl
return super.encode(c, offset, length);
}
}
-
+
/**
* {@inheritDoc}
*/
@Override
- public int encodeToCID( byte[] c, int offset, int length ) throws IOException
+ public int encodeToCID(byte[] c, int offset, int length) throws IOException
{
- if (type1CFont != null && getFontEncoding() == null)
- {
- return type1CFont.encodeToCID(c, offset, length);
- }
- else
- {
- return super.encodeToCID(c, offset, length);
- }
+ if (type1CFont != null && getFontEncoding() == null)
+ {
+ return type1CFont.encodeToCID(c, offset, length);
+ }
+ else
+ {
+ return super.encodeToCID(c, offset, length);
+ }
}
-
+
/**
* {@inheritDoc}
*/
@@ -509,45 +530,14 @@ public class PDType1Font extends PDSimpl
return super.getFontMatrix();
}
}
-
+
/**
- * {@inheritDoc}
+ * Returns the embedded Type1C font if available.
+ *
+ * @return the type1C font
*/
- @Override
- public GlyphVector remapGlyphs(GlyphVector glyphVector, String string)
+ public PDType1CFont getType1CFont()
{
- // this is used to fix an apparent bug with the sun jdk where the mapping of
- // character code to glyph index done by native code is wrong; this does not happen with openjdk
- try
- {
- Field fGlyphs = glyphVector.getClass().getDeclaredField("glyphs");
- fGlyphs.setAccessible(true);
- int[] glyphs = (int[]) fGlyphs.get(glyphVector);
- if (glyphs.length == 1 && glyphs[0] != 65535)
- {
- return glyphVector;
- }
- if (type1CFont != null)
- {
- Field fuserGlyphs = glyphVector.getClass().getDeclaredField("userGlyphs");
- fuserGlyphs.setAccessible(true);
- int[] userGlyphs = (int[]) fuserGlyphs.get(glyphVector);
- for (int j = 0; j < glyphs.length; j++)
- {
- if (glyphs[j] == 65535)
- {
- int c = (int) string.charAt(j);
- glyphs[j] = type1CFont.getGlyphIndex(c);
- userGlyphs[j] = type1CFont.getGlyphIndex(c);
- }
- }
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- return glyphVector;
+ return type1CFont;
}
-
}