You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2014/08/30 04:27:00 UTC
svn commit: r1621411 [2/7] - in /pdfbox/trunk: ./
examples/src/main/java/org/apache/pdfbox/examples/pdmodel/
fontbox/src/main/java/org/apache/fontbox/afm/
fontbox/src/main/java/org/apache/fontbox/cff/
fontbox/src/main/java/org/apache/fontbox/cff/charse...
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java Sat Aug 30 02:26:57 2014
@@ -34,21 +34,24 @@ public class Type2CharString extends Typ
private int defWidthX = 0;
private int nominalWidthX = 0;
private int pathCount = 0;
- private List<Object> type2sequence;
+ private final List<Object> type2sequence;
+ private final int gid;
/**
* Constructor.
- * @param reader Parent CFF font
+ * @param font Parent CFF font
* @param fontName font name
- * @param glyphName glyph name
+ * @param glyphName glyph name (or CID as hex string)
+ * @param gid GID
* @param sequence Type 2 char string sequence
* @param defaultWidthX default width
* @param nomWidthX nominal width
*/
- public Type2CharString(Type1CharStringReader reader, String fontName, String glyphName, List<Object> sequence,
+ public Type2CharString(Type1CharStringReader font, String fontName, String glyphName, int gid, List<Object> sequence,
int defaultWidthX, int nomWidthX)
{
- super(reader, fontName, glyphName);
+ super(font, fontName, glyphName);
+ this.gid = gid;
type2sequence = sequence;
defWidthX = defaultWidthX;
nominalWidthX = nomWidthX;
@@ -56,8 +59,15 @@ public class Type2CharString extends Typ
}
/**
- * Returns the advance width of the glyph.
- * @return the width
+ * Return the GID (glyph id) of this charstring.
+ */
+ public int getGID()
+ {
+ return gid;
+ }
+
+ /**
+ * Returns the advance width of this glyph.
*/
public int getWidth()
{
@@ -73,8 +83,7 @@ public class Type2CharString extends Typ
}
/**
- * Returns the Type 2 char string sequence.
- * @return the Type 2 sequence
+ * Returns the Type 2 charstring sequence.
*/
public List<Object> getType2Sequence()
{
@@ -138,7 +147,7 @@ public class Type2CharString extends Typ
}
else if ("endchar".equals(name))
{
- numbers = clearStack(numbers, numbers.size() == 5);
+ numbers = clearStack(numbers, numbers.size() == 5 || numbers.size() == 1);
closePath();
if (numbers.size() == 4)
{
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java Sat Aug 30 02:26:57 2014
@@ -32,7 +32,7 @@ public class Type2CharStringParser
private final String fontName, glyphName;
/**
- * Constructs a new Type1CharStringParser object.
+ * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
*
* @param fontName font name
* @param glyphName glyph name
@@ -44,6 +44,18 @@ public class Type2CharStringParser
}
/**
+ * Constructs a new Type1CharStringParser object for a CID-Keyed font.
+ *
+ * @param fontName font name
+ * @param cid CID
+ */
+ public Type2CharStringParser(String fontName, int cid)
+ {
+ this.fontName = fontName;
+ this.glyphName = String.format("%04x", cid); // for debugging only
+ }
+
+ /**
* The given byte array will be parsed and converted to a Type2 sequence.
* @param bytes the given mapping as byte array
* @param globalSubrIndex index containing all global subroutines
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java Sat Aug 30 02:26:57 2014
@@ -17,15 +17,12 @@
package org.apache.fontbox.cmap;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Iterator;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
/**
* This class represents a CMap file.
@@ -34,9 +31,6 @@ import org.apache.commons.logging.LogFac
*/
public class CMap
{
-
- private static final Log LOG = LogFactory.getLog(CMap.class);
-
private int wmode = 0;
private String cmapName = null;
private String cmapVersion = null;
@@ -45,44 +39,25 @@ public class CMap
private String registry = null;
private String ordering = null;
private int supplement = 0;
-
- private List<CodespaceRange> codeSpaceRanges = new ArrayList<CodespaceRange>();
- private Map<Integer,String> singleByteMappings = new HashMap<Integer,String>();
- private Map<Integer,String> doubleByteMappings = new HashMap<Integer,String>();
-
- private final Map<Integer,String> cid2charMappings = new HashMap<Integer,String>();
- private final Map<String,Integer> char2CIDMappings = new HashMap<String,Integer>();
- private final List<CIDRange> cidRanges = new LinkedList<CIDRange>();
+
+ // code lengths
+ private final List<CodespaceRange> codespaceRanges = new ArrayList<CodespaceRange>();
+
+ // Unicode mappings
+ private final Map<Integer,String> charToUnicode = new HashMap<Integer,String>();
+
+ // CID mappings
+ private final Map<Integer,Integer> codeToCid = new HashMap<Integer,Integer>();
+ private final List<CIDRange> codeToCidRanges = new LinkedList<CIDRange>();
private static final String SPACE = " ";
private int spaceMapping = -1;
-
+
/**
* Creates a new instance of CMap.
*/
- public CMap()
- {
- //default constructor
- }
-
- /**
- * This will tell if this cmap has any one byte mappings.
- *
- * @return true If there are any one byte mappings, false otherwise.
- */
- public boolean hasOneByteMappings()
+ CMap()
{
- return singleByteMappings.size() > 0;
- }
-
- /**
- * This will tell if this cmap has any two byte mappings.
- *
- * @return true If there are any two byte mappings, false otherwise.
- */
- public boolean hasTwoByteMappings()
- {
- return doubleByteMappings.size() > 0;
}
/**
@@ -92,104 +67,143 @@ public class CMap
*/
public boolean hasCIDMappings()
{
- return !char2CIDMappings.isEmpty() || !cidRanges.isEmpty();
+ return !codeToCid.isEmpty() || !codeToCidRanges.isEmpty();
}
/**
- * This will perform a lookup into the map.
+ * This will tell if this cmap has any Unicode mappings.
*
- * @param code The code used to lookup.
- * @param offset The offset into the byte array.
- * @param length The length of the data we are getting.
- *
- * @return The string that matches the lookup.
+ * @return true If there are any Unicode mappings, false otherwise.
*/
- public String lookup( byte[] code, int offset, int length )
+ public boolean hasUnicodeMappings()
{
- return lookup(getCodeFromArray(code, offset, length), length);
+ return !charToUnicode.isEmpty();
}
/**
- * This will perform a lookup into the map.
- *
- * @param code The code used to lookup.
- * @param length The length of the data we are getting.
+ * Returns the sequence of Unicode characters for the given character code.
*
- * @return The string that matches the lookup.
+ * @param code character code
+ * @return Unicode characters (may be more than one, e.g "fi" ligature)
*/
- public String lookup( int code, int length )
+ public String toUnicode(int code)
{
- String result = null;
- if( length == 1 )
- {
- result = singleByteMappings.get( code );
- }
- else if( length == 2 )
- {
- result = doubleByteMappings.get( code );
- }
- return result;
+ return charToUnicode.get(code);
}
-
+
/**
- * This will perform a lookup into the CID map.
+ * Reads a character code from a string in the content stream.
+ * <p>>See "CMap Mapping" and "Handling Undefined Characters" in PDF32000 for more details.
*
- * @param cid The CID used to lookup.
- *
- * @return The string that matches the lookup.
+ * @param in string stream
+ * @return character code
+ * @throws IOException if there was an error reading the stream or CMap
*/
- public String lookupCID(int cid)
+ public int readCode(InputStream in) throws IOException
{
- if (cid2charMappings.containsKey(cid))
- {
- return cid2charMappings.get(cid);
- }
- else
+ // save the position in the string
+ in.mark(4);
+
+ // mapping algorithm
+ List<Byte> bytes = new ArrayList<Byte>(4);
+ for (int i = 0; i < 4; i++)
{
- for (CIDRange range : cidRanges)
+ bytes.add((byte)in.read());
+ for (CodespaceRange range : codespaceRanges)
{
- int ch = range.unmap(cid);
- if (ch != -1)
+ if (range.isFullMatch(bytes))
{
- return Character.toString((char) ch);
+ return toInt(bytes);
}
}
- return null;
}
+
+ // reset to the original position in the string
+ in.reset();
+
+ // modified mapping algorithm
+ bytes = new ArrayList<Byte>(4);
+ for (int i = 0; i < 4; i++)
+ {
+ bytes.add((byte)in.read());
+ CodespaceRange match = null;
+ CodespaceRange shortest = null;
+ for (CodespaceRange range : codespaceRanges)
+ {
+ if (range.isPartialMatch(bytes.get(i), i));
+ {
+ if (match == null)
+ {
+ match = range;
+ }
+ else if (range.getStart().length < match.getStart().length)
+ {
+ // for multiple matches, choose the codespace with the shortest codes
+ match = range;
+ }
+ }
+
+ // find shortest range
+ if (shortest == null || range.getStart().length < shortest.getStart().length)
+ {
+ shortest = range;
+ }
+ }
+
+ // if there are no matches, the range with the shortest codes is chosen
+ if (match == null)
+ {
+ match = shortest;
+ }
+
+ // we're done when we have enough bytes for the matched range
+ if (match.getStart().length == bytes.size())
+ {
+ return toInt(bytes);
+ }
+ }
+
+ throw new IOException("CMap is invalid");
}
/**
- * This will perform a lookup into the CID map.
- *
- * @param code The code used to lookup.
- * @param offset the offset into the array.
- * @param length the length of the subarray.
+ * Returns an int given a List<Byte>
+ */
+ private int toInt(List<Byte> data)
+ {
+ int code = 0;
+ for (byte b : data)
+ {
+ code <<= 8;
+ code |= (b + 256) % 256;
+ }
+ return code;
+ }
+
+ /**
+ * Returns the CID for the given character code.
*
- * @return The CID that matches the lookup.
+ * @param code character code
+ * @return CID
*/
- public int lookupCID(byte[] code, int offset, int length)
+ public int toCID(int code)
{
- if (isInCodeSpaceRanges(code,offset,length))
+ if (codeToCid.containsKey(code))
{
- int codeAsInt = getCodeFromArray(code, offset, length);
- if (char2CIDMappings.containsKey(codeAsInt))
- {
- return char2CIDMappings.get(codeAsInt);
- }
- else
+ return codeToCid.get(code);
+ }
+ else
+ {
+ for (CIDRange range : codeToCidRanges)
{
- for (CIDRange range : cidRanges)
+ int ch = range.map((char)code);
+ if (ch != -1)
{
- int ch = range.map((char)codeAsInt);
- if (ch != -1)
- {
- return ch;
- }
+ return ch;
}
- return -1;
}
+ return 0;
}
- return -1;
}
/**
@@ -211,49 +225,32 @@ public class CMap
}
/**
- * This will add a mapping.
- *
- * @param src The src to the mapping.
- * @param dest The dest to the mapping.
+ * This will add a character code to Unicode character sequence mapping.
*
- * @throws IOException if the src is invalid.
+ * @param codes The character codes to map from.
+ * @param unicode The Unicode characters to map to.
*/
- public void addMapping( byte[] src, String dest ) throws IOException
+ void addCharMapping(byte[] codes, String unicode)
{
-
- int srcLength = src.length;
- int intSrc = getCodeFromArray(src, 0, srcLength);
- if ( SPACE.equals(dest) )
- {
- spaceMapping = intSrc;
- }
- if( srcLength == 1 )
- {
- singleByteMappings.put( intSrc, dest );
- }
- else if( srcLength == 2 )
- {
- doubleByteMappings.put( intSrc, dest );
- }
- else
+ int code = getCodeFromArray(codes, 0, codes.length);
+ charToUnicode.put(code, unicode);
+
+ // fixme: ugly little hack
+ if (SPACE.equals(unicode))
{
- // Just log the invalid entry instead of throwing an exception
- LOG.error("Mapping code should be 1 or two bytes and not " + src.length);
+ spaceMapping = code;
}
}
/**
* This will add a CID mapping.
*
- * @param src The CID to the mapping.
- * @param dest The dest to the mapping.
- *
- * @throws IOException if the src is invalid.
+ * @param code character code
+ * @param cid CID
*/
- public void addCIDMapping( int src, String dest ) throws IOException
+ void addCIDMapping(int code, int cid)
{
- cid2charMappings.put( src, dest );
- char2CIDMappings.put( dest, src );
+ codeToCid.put(cid, code);
}
/**
@@ -264,9 +261,9 @@ public class CMap
* @param cid the cid to be started with.
*
*/
- public void addCIDRange(char from, char to, int cid)
+ void addCIDRange(char from, char to, int cid)
{
- cidRanges.add(0, new CIDRange(from, to, cid));
+ codeToCidRanges.add(0, new CIDRange(from, to, cid));
}
/**
@@ -274,19 +271,9 @@ public class CMap
*
* @param range A single codespace range.
*/
- public void addCodespaceRange( CodespaceRange range )
+ void addCodespaceRange( CodespaceRange range )
{
- codeSpaceRanges.add( range );
- }
-
- /**
- * Getter for property codeSpaceRanges.
- *
- * @return Value of property codeSpaceRanges.
- */
- public List<CodespaceRange> getCodeSpaceRanges()
- {
- return codeSpaceRanges;
+ codespaceRanges.add(range);
}
/**
@@ -295,46 +282,12 @@ public class CMap
*
* @param cmap The cmap to load mappings from.
*/
- public void useCmap( CMap cmap )
- {
- this.codeSpaceRanges.addAll( cmap.codeSpaceRanges );
- this.singleByteMappings.putAll( cmap.singleByteMappings );
- this.doubleByteMappings.putAll( cmap.doubleByteMappings );
- }
-
- /**
- * Check whether the given byte array is in codespace ranges or not.
- *
- * @param code The byte array to look for in the codespace range.
- *
- * @return true if the given byte array is in the codespace range.
- */
- public boolean isInCodeSpaceRanges( byte[] code )
+ void useCmap( CMap cmap )
{
- return isInCodeSpaceRanges(code, 0, code.length);
- }
-
- /**
- * Check whether the given byte array is in codespace ranges or not.
- *
- * @param code The byte array to look for in the codespace range.
- * @param offset The starting offset within the byte array.
- * @param length The length of the part of the array.
- *
- * @return true if the given byte array is in the codespace range.
- */
- public boolean isInCodeSpaceRanges( byte[] code, int offset, int length )
- {
- Iterator<CodespaceRange> it = codeSpaceRanges.iterator();
- while ( it.hasNext() )
- {
- CodespaceRange range = it.next();
- if ( range != null && range.isInRange(code, offset, length) )
- {
- return true;
- }
- }
- return false;
+ this.codespaceRanges.addAll(cmap.codespaceRanges);
+ this.charToUnicode.putAll(cmap.charToUnicode);
+ this.codeToCid.putAll(cmap.codeToCid);
+ this.codeToCidRanges.addAll(cmap.codeToCidRanges);
}
/**
@@ -488,4 +441,10 @@ public class CMap
{
return spaceMapping;
}
-}
\ No newline at end of file
+
+ @Override
+ public String toString()
+ {
+ return cmapName;
+ }
+}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java Sat Aug 30 02:26:57 2014
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -30,35 +29,12 @@ import java.util.Map;
import org.apache.fontbox.util.ResourceLoader;
/**
- * This will parse a CMap stream.
+ * Parses a CMap stream.
*
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- *
+ * @author Ben Litchfield
*/
public class CMapParser
{
- private static final String BEGIN_CODESPACE_RANGE = "begincodespacerange";
- private static final String BEGIN_BASE_FONT_CHAR = "beginbfchar";
- private static final String BEGIN_BASE_FONT_RANGE = "beginbfrange";
- private static final String BEGIN_CID_CHAR = "begincidchar";
- private static final String BEGIN_CID_RANGE = "begincidrange";
- private static final String USECMAP = "usecmap";
-
- private static final String END_CODESPACE_RANGE = "endcodespacerange";
- private static final String END_BASE_FONT_CHAR = "endbfchar";
- private static final String END_BASE_FONT_RANGE = "endbfrange";
- private static final String END_CID_CHAR = "endcidchar";
- private static final String END_CID_RANGE = "endcidrange";
- private static final String END_CMAP = "endcmap";
-
- private static final String WMODE = "WMode";
- private static final String CMAP_NAME = "CMapName";
- private static final String CMAP_VERSION = "CMapVersion";
- private static final String CMAP_TYPE = "CMapType";
- private static final String REGISTRY = "Registry";
- private static final String ORDERING = "Ordering";
- private static final String SUPPLEMENT = "Supplement";
-
private static final String MARK_END_OF_DICTIONARY = ">>";
private static final String MARK_END_OF_ARRAY = "]";
@@ -121,7 +97,7 @@ public class CMapParser
if (token instanceof Operator)
{
Operator op = (Operator) token;
- if (op.op.equals(USECMAP))
+ if (op.op.equals("usecmap"))
{
LiteralName useCmapName = (LiteralName) previousToken;
InputStream useStream = ResourceLoader.loadResource(resourceRoot + useCmapName.name);
@@ -132,12 +108,12 @@ public class CMapParser
CMap useCMap = parse(resourceRoot, useStream);
result.useCmap(useCMap);
}
- else if (op.op.equals(END_CMAP))
+ else if (op.op.equals("endcmap"))
{
// end of CMap reached, stop reading as there isn't any interesting info anymore
break;
}
- else if (op.op.equals(BEGIN_CODESPACE_RANGE))
+ else if (op.op.equals("begincodespacerange"))
{
Number cosCount = (Number) previousToken;
for (int j = 0; j < cosCount.intValue(); j++)
@@ -145,7 +121,7 @@ public class CMapParser
Object nextToken = parseNextToken(cmapStream);
if (nextToken instanceof Operator)
{
- if (!((Operator) nextToken).op.equals(END_CODESPACE_RANGE))
+ if (!((Operator) nextToken).op.equals("endcodespacerange"))
{
throw new IOException("Error : ~codespacerange contains an unexpected operator : "
+ ((Operator) nextToken).op);
@@ -160,7 +136,7 @@ public class CMapParser
result.addCodespaceRange(range);
}
}
- else if (op.op.equals(BEGIN_BASE_FONT_CHAR))
+ else if (op.op.equals("beginbfchar"))
{
Number cosCount = (Number) previousToken;
for (int j = 0; j < cosCount.intValue(); j++)
@@ -168,7 +144,7 @@ public class CMapParser
Object nextToken = parseNextToken(cmapStream);
if (nextToken instanceof Operator)
{
- if (!((Operator) nextToken).op.equals(END_BASE_FONT_CHAR))
+ if (!((Operator) nextToken).op.equals("endbfchar"))
{
throw new IOException("Error : ~bfchar contains an unexpected operator : "
+ ((Operator) nextToken).op);
@@ -181,11 +157,11 @@ public class CMapParser
{
byte[] bytes = (byte[]) nextToken;
String value = createStringFromBytes(bytes);
- result.addMapping(inputCode, value);
+ result.addCharMapping(inputCode, value);
}
else if (nextToken instanceof LiteralName)
{
- result.addMapping(inputCode, ((LiteralName) nextToken).name);
+ result.addCharMapping(inputCode, ((LiteralName) nextToken).name);
}
else
{
@@ -194,7 +170,7 @@ public class CMapParser
}
}
}
- else if (op.op.equals(BEGIN_BASE_FONT_RANGE))
+ else if (op.op.equals("beginbfrange"))
{
Number cosCount = (Number) previousToken;
@@ -203,7 +179,7 @@ public class CMapParser
Object nextToken = parseNextToken(cmapStream);
if (nextToken instanceof Operator)
{
- if (!((Operator) nextToken).op.equals(END_BASE_FONT_RANGE))
+ if (!((Operator) nextToken).op.equals("endbfrange"))
{
throw new IOException("Error : ~bfrange contains an unexpected operator : "
+ ((Operator) nextToken).op);
@@ -226,10 +202,10 @@ public class CMapParser
}
boolean done = false;
// don't add 1:1 mappings to reduce the memory footprint
- if (Arrays.equals(startCode, tokenBytes))
+ /*if (Arrays.equals(startCode, tokenBytes))
{
done = true;
- }
+ }*/
String value = null;
int arrayIndex = 0;
@@ -240,7 +216,7 @@ public class CMapParser
done = true;
}
value = createStringFromBytes(tokenBytes);
- result.addMapping(startCode, value);
+ result.addCharMapping(startCode, value);
increment(startCode);
if (array == null)
@@ -258,7 +234,7 @@ public class CMapParser
}
}
}
- else if (op.op.equals(BEGIN_CID_CHAR))
+ else if (op.op.equals("begincidchar"))
{
Number cosCount = (Number) previousToken;
for (int j = 0; j < cosCount.intValue(); j++)
@@ -266,7 +242,7 @@ public class CMapParser
Object nextToken = parseNextToken(cmapStream);
if (nextToken instanceof Operator)
{
- if (!((Operator) nextToken).op.equals(END_CID_CHAR))
+ if (!((Operator) nextToken).op.equals("endcidchar"))
{
throw new IOException("Error : ~cidchar contains an unexpected operator : "
+ ((Operator) nextToken).op);
@@ -275,11 +251,11 @@ public class CMapParser
}
byte[] inputCode = (byte[]) nextToken;
int mappedCode = (Integer) parseNextToken(cmapStream);
- String mappedStr = createStringFromBytes(inputCode);
- result.addCIDMapping(mappedCode, mappedStr);
+ int mappedCID = createIntFromBytes(inputCode);
+ result.addCIDMapping(mappedCode, mappedCID);
}
}
- else if (op.op.equals(BEGIN_CID_RANGE))
+ else if (op.op.equals("begincidrange"))
{
int numberOfLines = (Integer) previousToken;
for (int n = 0; n < numberOfLines; n++)
@@ -287,7 +263,7 @@ public class CMapParser
Object nextToken = parseNextToken(cmapStream);
if (nextToken instanceof Operator)
{
- if (!((Operator) nextToken).op.equals(END_CID_RANGE))
+ if (!((Operator) nextToken).op.equals("endcidrange"))
{
throw new IOException("Error : ~cidrange contains an unexpected operator : "
+ ((Operator) nextToken).op);
@@ -309,8 +285,8 @@ public class CMapParser
int endOfMappings = mappedCode + end - start;
while (mappedCode <= endOfMappings)
{
- String mappedStr = createStringFromBytes(startCode);
- result.addCIDMapping(mappedCode++, mappedStr);
+ int mappedCID = createIntFromBytes(startCode);
+ result.addCIDMapping(mappedCode++, mappedCID);
increment(startCode);
}
}
@@ -320,7 +296,7 @@ public class CMapParser
else if (token instanceof LiteralName)
{
LiteralName literal = (LiteralName) token;
- if (WMODE.equals(literal.name))
+ if ("WMode".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof Integer)
@@ -328,7 +304,7 @@ public class CMapParser
result.setWMode((Integer) next);
}
}
- else if (CMAP_NAME.equals(literal.name))
+ else if ("CMapName".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof LiteralName)
@@ -336,7 +312,7 @@ public class CMapParser
result.setName(((LiteralName) next).name);
}
}
- else if (CMAP_VERSION.equals(literal.name))
+ else if ("CMapVersion".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof Number)
@@ -348,7 +324,7 @@ public class CMapParser
result.setVersion((String) next);
}
}
- else if (CMAP_TYPE.equals(literal.name))
+ else if ("CMapType".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof Integer)
@@ -356,7 +332,7 @@ public class CMapParser
result.setType((Integer) next);
}
}
- else if (REGISTRY.equals(literal.name))
+ else if ("Registry".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof String)
@@ -364,7 +340,7 @@ public class CMapParser
result.setRegistry((String) next);
}
}
- else if (ORDERING.equals(literal.name))
+ else if ("Ordering".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof String)
@@ -372,7 +348,7 @@ public class CMapParser
result.setOrdering((String) next);
}
}
- else if (SUPPLEMENT.equals(literal.name))
+ else if ("Supplement".equals(literal.name))
{
Object next = parseNextToken(cmapStream);
if (next instanceof Integer)
@@ -703,24 +679,4 @@ public class CMapParser
op = theOp;
}
}
-
- /**
- * A simple class to test parsing of cmap files.
- *
- * @param args Some command line arguments.
- *
- * @throws Exception If there is an error parsing the file.
- */
- public static void main(String[] args) throws Exception
- {
- if (args.length != 1)
- {
- System.err.println("usage: java org.apache.fontbox.cmap.CMapParser <CMAP File>");
- System.exit(-1);
- }
- CMapParser parser = new CMapParser();
- File cmapFile = new File(args[0]);
- CMap result = parser.parse(cmapFile);
- System.out.println("Result:" + result);
- }
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java Sat Aug 30 02:26:57 2014
@@ -16,15 +16,15 @@
*/
package org.apache.fontbox.cmap;
+import java.util.List;
+
/**
* This represents a single entry in the codespace range.
*
- * @author Ben Litchfield (ben@benlitchfield.com)
- * @version $Revision: 1.1 $
+ * @author Ben Litchfield
*/
public class CodespaceRange
{
-
private byte[] start;
private byte[] end;
@@ -48,7 +48,7 @@ public class CodespaceRange
* @param endBytes New value of property end.
*
*/
- public void setEnd(byte[] endBytes)
+ void setEnd(byte[] endBytes)
{
end = endBytes;
}
@@ -66,50 +66,69 @@ public class CodespaceRange
* @param startBytes New value of property start.
*
*/
- public void setStart(byte[] startBytes)
+ void setStart(byte[] startBytes)
{
start = startBytes;
}
/**
- * Check whether the given byte array is in this codespace range or ot.
- * @param code The byte array to look for in the codespace range.
- * @param offset The starting offset within the byte array.
- * @param length The length of the part of the array.
- *
- * @return true if the given byte array is in the codespace range.
+ * Returns true if the given code bytes match this codespace range.
*/
- public boolean isInRange(byte[] code, int offset, int length)
+ public boolean matches(byte[] code)
{
- if ( length < start.length || length > end.length )
- {
- return false;
- }
-
- if ( end.length == length )
+ // code must be the same length as the bounding codes
+ if (code.length >= start.length && code.length <= end.length)
{
- for ( int i = 0; i < end.length; i++ )
+ // each of it bytes must lie between the corresponding bytes of the upper & lower bounds
+ for (int i = 0; i < code.length; i++)
{
- int endInt = ((int)end[i]) & 0xFF;
- int codeInt = ((int)code[offset + i]) & 0xFF;
- if ( endInt < codeInt )
+ int startNum = start[i] & 0xff;
+ int endNum = end[i] & 0xff;
+ int codeNum = code[i] & 0xff;
+
+ if (codeNum > endNum || codeNum < startNum)
{
return false;
}
}
+ return true;
}
- if ( start.length == length )
+ return false;
+ }
+
+ /**
+ * Returns true if the given code bytes match this codespace range.
+ */
+ public boolean isFullMatch(List<Byte> code)
+ {
+ // code must be the same length as the bounding codes
+ if (code.size() >= start.length && code.size() <= end.length)
{
- for ( int i = 0; i < end.length; i++ )
+ // each of it bytes must lie between the corresponding bytes of the upper & lower bounds
+ for (int i = 0; i < code.size(); i++)
{
- int startInt = ((int)start[i]) & 0xFF;
- int codeInt = ((int)code[offset + i]) & 0xFF;
- if ( startInt > codeInt )
+ int startNum = start[i] & 0xff;
+ int endNum = end[i] & 0xff;
+ int codeNum = code.get(i) & 0xff;
+
+ if (codeNum > endNum || codeNum < startNum)
{
return false;
}
}
+ return true;
}
- return true;
+ return false;
+ }
+
+ /**
+ * Returns true if the given byte matches the byte at the given index of this codespace range.
+ */
+ public boolean isPartialMatch(byte b, int index)
+ {
+ int startNum = start[index] & 0xff;
+ int endNum = end[index] & 0xff;
+ int codeNum = b & 0xff;
+ return !(codeNum > endNum || codeNum < startNum);
}
-}
\ No newline at end of file
+}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java Sat Aug 30 02:26:57 2014
@@ -22,98 +22,26 @@ import java.util.HashMap;
import java.util.Map;
/**
- * This is an interface to a text encoder.
+ * A PostScript Encoding vector.
*
* @author Ben Litchfield
- *
*/
public abstract class Encoding
{
- /**
- * The number of standard mac glyph names.
- */
- public static final int NUMBER_OF_MAC_GLYPHS = 258;
-
- /**
- * The 258 standard mac glyph names a used in 'post' format 1 and 2.
- */
- public static final String[] MAC_GLYPH_NAMES = new String[]
- {
- ".notdef",".null", "nonmarkingreturn", "space", "exclam", "quotedbl",
- "numbersign", "dollar", "percent", "ampersand", "quotesingle",
- "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen",
- "period", "slash", "zero", "one", "two", "three", "four", "five",
- "six", "seven", "eight", "nine", "colon", "semicolon", "less",
- "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
- "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
- "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
- "bracketright", "asciicircum", "underscore", "grave", "a", "b",
- "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
- "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft",
- "bar", "braceright", "asciitilde", "Adieresis", "Aring",
- "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute",
- "agrave", "acircumflex", "adieresis", "atilde", "aring",
- "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis",
- "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute",
- "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave",
- "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
- "section", "bullet", "paragraph", "germandbls", "registered",
- "copyright", "trademark", "acute", "dieresis", "notequal", "AE",
- "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
- "yen", "mu", "partialdiff", "summation", "product", "pi",
- "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash",
- "questiondown", "exclamdown", "logicalnot", "radical", "florin",
- "approxequal", "Delta", "guillemotleft", "guillemotright",
- "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE",
- "oe", "endash", "emdash", "quotedblleft", "quotedblright",
- "quoteleft", "quoteright", "divide", "lozenge", "ydieresis",
- "Ydieresis", "fraction", "currency", "guilsinglleft",
- "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered",
- "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
- "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
- "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
- "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
- "circumflex", "tilde", "macron", "breve", "dotaccent", "ring",
- "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash",
- "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
- "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply",
- "onesuperior", "twosuperior", "threesuperior", "onehalf",
- "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
- "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron",
- "ccaron", "dcroat"
- };
-
- /**
- * The indices of the standard mac glyph names.
- */
- public static Map<String,Integer> MAC_GLYPH_NAMES_INDICES;
-
- static
- {
- MAC_GLYPH_NAMES_INDICES = new HashMap<String,Integer>();
- for (int i=0;i<Encoding.NUMBER_OF_MAC_GLYPHS;++i)
- {
- MAC_GLYPH_NAMES_INDICES.put(Encoding.MAC_GLYPH_NAMES[i],i);
- }
- }
-
- /**
- * Identifies a non-mapped character.
- */
private static final String NOTDEF = ".notdef";
+ private static final Map<String,String> NAME_TO_CHARACTER = new HashMap<String,String>();
+ private static final Map<String,String> CHARACTER_TO_NAME = new HashMap<String,String>();
/**
* This is a mapping from a character code to a character name.
*/
protected Map<Integer,String> codeToName = new HashMap<Integer,String>();
+
/**
* This is a mapping from a character name to a character code.
*/
protected Map<String,Integer> nameToCode = new HashMap<String,Integer>();
- private static final Map<String,String> NAME_TO_CHARACTER = new HashMap<String,String>();
- private static final Map<String,String> CHARACTER_TO_NAME = new HashMap<String,String>();
-
/**
* This will add a character encoding.
*
@@ -130,7 +58,6 @@ public abstract class Encoding
* This will get the character code for the name.
*
* @param name The name of the character.
- *
* @return The code for the character or null if it is not in the encoding.
*/
public Integer getCode( String name )
@@ -142,7 +69,6 @@ public abstract class Encoding
* This will take a character code and get the name from the code.
*
* @param code The character code.
- *
* @return The name of the character.
*/
public String getName( int code )
@@ -159,9 +85,7 @@ public abstract class Encoding
* This will take a character code and get the name from the code.
*
* @param c The character.
- *
* @return The name of the character.
- *
* @throws IOException If there is no name for the character.
*/
public String getNameFromCharacter( char c ) throws IOException
@@ -178,9 +102,7 @@ public abstract class Encoding
* This will get the character from the code.
*
* @param code The character code.
- *
* @return The printable character for the code.
- *
* @throws IOException If there is not name for the character.
*/
public String getCharacter( int code ) throws IOException
@@ -192,7 +114,6 @@ public abstract class Encoding
* This will get the character from the name.
*
* @param name The name of the character.
- *
* @return The printable character for the code.
*/
public static String getCharacter( String name )
@@ -206,7 +127,7 @@ public abstract class Encoding
}
/**
- * Returns an unmodifiable view of the Code2Name mapping.
+ * Returns an unmodifiable view of the code to name mapping.
*
* @return the Code2Name map
*/
@@ -214,5 +135,4 @@ public abstract class Encoding
{
return Collections.unmodifiableMap(codeToName);
}
-
-}
\ No newline at end of file
+}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java Sat Aug 30 02:26:57 2014
@@ -186,26 +186,18 @@ public class GlyfSimpleDescript extends
*/
private void readFlags(int flagCount, TTFDataStream bais) throws IOException
{
- try
+ for (int index = 0; index < flagCount; index++)
{
- for (int index = 0; index < flagCount; index++)
+ flags[index] = (byte) bais.readUnsignedByte();
+ if ((flags[index] & REPEAT) != 0)
{
- flags[index] = (byte) bais.readUnsignedByte();
- if ((flags[index] & REPEAT) != 0)
+ int repeats = bais.readUnsignedByte();
+ for (int i = 1; i <= repeats; i++)
{
- int repeats = bais.readUnsignedByte();
- for (int i = 1; i <= repeats; i++)
- {
- flags[index + i] = flags[index];
- }
- index += repeats;
+ flags[index + i] = flags[index];
}
+ index += repeats;
}
}
- catch (ArrayIndexOutOfBoundsException e)
- {
- LOG.error("error: array index out of bounds", e);
- }
}
-
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java Sat Aug 30 02:26:57 2014
@@ -214,7 +214,7 @@ class GlyphRenderer
path.closePath();
if (LOG.isDebugEnabled())
{
- LOG.debug("closePath");
+ LOG.trace("closePath");
}
}
@@ -223,7 +223,7 @@ class GlyphRenderer
path.moveTo(point.x, point.y);
if (LOG.isDebugEnabled())
{
- LOG.debug("moveTo: " + String.format("%d,%d", point.x, point.y));
+ LOG.trace("moveTo: " + String.format("%d,%d", point.x, point.y));
}
}
@@ -232,7 +232,7 @@ class GlyphRenderer
path.lineTo(point.x, point.y);
if (LOG.isDebugEnabled())
{
- LOG.debug("lineTo: " + String.format("%d,%d", point.x, point.y));
+ LOG.trace("lineTo: " + String.format("%d,%d", point.x, point.y));
}
}
@@ -241,7 +241,7 @@ class GlyphRenderer
path.quadTo(ctrlPoint.x, ctrlPoint.y, point.x, point.y);
if (LOG.isDebugEnabled())
{
- LOG.debug("quadTo: " + String.format("%d,%d %d,%d", ctrlPoint.x, ctrlPoint.y,
+ LOG.trace("quadTo: " + String.format("%d,%d %d,%d", ctrlPoint.x, ctrlPoint.y,
point.x, point.y));
}
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java Sat Aug 30 02:26:57 2014
@@ -46,21 +46,31 @@ public class HorizontalMetricsTable exte
HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
int numHMetrics = hHeader.getNumberOfHMetrics();
int numGlyphs = ttf.getNumberOfGlyphs();
-
+
+ int bytesRead = 0;
advanceWidth = new int[ numHMetrics ];
leftSideBearing = new short[ numHMetrics ];
for( int i=0; i<numHMetrics; i++ )
{
advanceWidth[i] = data.readUnsignedShort();
leftSideBearing[i] = data.readSignedShort();
+ bytesRead += 4;
}
-
- int numberNonHorizontal = numGlyphs - numHMetrics;
- nonHorizontalLeftSideBearing = new short[ numberNonHorizontal ];
- for( int i=0; i<numberNonHorizontal; i++ )
+
+ if (bytesRead < getLength())
{
- nonHorizontalLeftSideBearing[i] = data.readSignedShort();
+ int numberNonHorizontal = numGlyphs - numHMetrics;
+ nonHorizontalLeftSideBearing = new short[ numberNonHorizontal ];
+ for( int i=0; i<numberNonHorizontal; i++ )
+ {
+ if (bytesRead < getLength())
+ {
+ nonHorizontalLeftSideBearing[i] = data.readSignedShort();
+ bytesRead += 2;
+ }
+ }
}
+
initialized = true;
}
/**
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java Sat Aug 30 02:26:57 2014
@@ -21,72 +21,49 @@ import java.io.IOException;
/**
* A name record in the name table.
*
- * @author Ben Litchfield (ben@benlitchfield.com)
- * @version $Revision: 1.1 $
+ * @author Ben Litchfield
*/
public class NameRecord
{
- /**
- * A constant for the platform.
- */
- public static final int PLATFORM_APPLE_UNICODE = 0;
- /**
- * A constant for the platform.
- */
+ // platform ids
+ public static final int PLATFORM_UNICODE = 0;
public static final int PLATFORM_MACINTOSH = 1;
- /**
- * A constant for the platform.
- */
public static final int PLATFORM_ISO = 2;
- /**
- * A constant for the platform.
- */
public static final int PLATFORM_WINDOWS = 3;
-
- /**
- * Platform specific encoding.
- */
- public static final int PLATFORM_ENCODING_WINDOWS_UNDEFINED = 0;
- /**
- * Platform specific encoding.
- */
- public static final int PLATFORM_ENCODING_WINDOWS_UNICODE = 1;
-
- /**
- * A name id.
- */
+
+ // Unicode encoding ids
+ public static final int ENCODING_UNICODE_1_0 = 0;
+ public static final int ENCODING_UNICODE_1_1 = 1;
+ public static final int ENCODING_UNICODE_2_0_BMP = 3;
+ public static final int ENCODING_UNICODE_2_0_FULL = 4;
+
+ // Unicode encoding ids
+ public static final int LANGUGAE_UNICODE = 0;
+
+ // Windows encoding ids
+ public static final int ENCODING_WINDOWS_SYMBOL = 0;
+ public static final int ENCODING_WINDOWS_UNICODE_BMP = 1;
+ public static final int ENCODING_WINDOWS_UNICODE_UCS4 = 10;
+
+ // Windows language ids
+ public static final int LANGUGAE_WINDOWS_EN_US = 0x0409;
+
+ // Macintosh encoding ids
+ public static final int ENCODING_MACINTOSH_ROMAN = 0;
+
+ // Macintosh language ids
+ public static final int LANGUGAE_MACINTOSH_ENGLISH = 0;
+
+ // name ids
public static final int NAME_COPYRIGHT = 0;
- /**
- * A name id.
- */
public static final int NAME_FONT_FAMILY_NAME = 1;
- /**
- * A name id.
- */
public static final int NAME_FONT_SUB_FAMILY_NAME = 2;
- /**
- * A name id.
- */
public static final int NAME_UNIQUE_FONT_ID = 3;
- /**
- * A name id.
- */
public static final int NAME_FULL_FONT_NAME = 4;
- /**
- * A name id.
- */
public static final int NAME_VERSION = 5;
- /**
- * A name id.
- */
public static final int NAME_POSTSCRIPT_NAME = 6;
- /**
- * A name id.
- */
public static final int NAME_TRADEMARK = 7;
-
-
private int platformId;
private int platformEncodingId;
private int languageId;
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java Sat Aug 30 02:26:57 2014
@@ -19,13 +19,14 @@ package org.apache.fontbox.ttf;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* A table in a true type font.
*
- * @author Ben Litchfield (ben@benlitchfield.com)
- *
+ * @author Ben Litchfield
*/
public class NamingTable extends TTFTable
{
@@ -35,12 +36,14 @@ public class NamingTable extends TTFTabl
public static final String TAG = "name";
private List<NameRecord> nameRecords = new ArrayList<NameRecord>();
-
+
+ private Map<Integer, Map<Integer, Map<Integer, Map<Integer, String>>>> lookupTable =
+ new HashMap<Integer, Map<Integer, Map<Integer, Map<Integer, String>>>>();
+
private String fontFamily = null;
private String fontSubFamily = null;
private String psName = null;
-
-
+
/**
* This will read the required data from the stream.
*
@@ -53,80 +56,173 @@ public class NamingTable extends TTFTabl
int formatSelector = data.readUnsignedShort();
int numberOfNameRecords = data.readUnsignedShort();
int offsetToStartOfStringStorage = data.readUnsignedShort();
- for( int i=0; i< numberOfNameRecords; i++ )
+ for (int i=0; i< numberOfNameRecords; i++)
{
NameRecord nr = new NameRecord();
- nr.initData( ttf, data );
- nameRecords.add( nr );
+ nr.initData(ttf, data);
+ nameRecords.add(nr);
}
- for( int i=0; i<numberOfNameRecords; i++ )
+
+ for (int i=0; i<numberOfNameRecords; i++)
{
- NameRecord nr = nameRecords.get( i );
- data.seek( getOffset() + (2*3)+numberOfNameRecords*2*6+nr.getStringOffset() );
+ NameRecord nr = nameRecords.get(i);
+ data.seek(getOffset() + (2*3)+numberOfNameRecords*2*6+nr.getStringOffset());
int platform = nr.getPlatformId();
int encoding = nr.getPlatformEncodingId();
String charset = "ISO-8859-1";
- boolean isPlatform310 = false;
- boolean isPlatform10 = false;
- if( platform == 3 && (encoding == 1 || encoding == 0) )
+ if (platform == 3 && (encoding == 1 || encoding == 0))
{
charset = "UTF-16";
- isPlatform310 = true;
}
- else if( platform == 2 )
+ else if (platform == 2)
{
- if( encoding == 0 )
+ if (encoding == 0)
{
charset = "US-ASCII";
}
- else if( encoding == 1 )
+ else if (encoding == 1)
{
//not sure is this is correct??
charset = "ISO-10646-1";
}
- else if( encoding == 2 )
+ else if (encoding == 2)
{
charset = "ISO-8859-1";
}
}
- else if ( platform == 1 && encoding == 0)
+ String string = data.readString(nr.getStringLength(), charset);
+ nr.setString(string);
+ }
+
+ // build multi-dimensional lookup table
+ for (NameRecord nr : nameRecords)
+ {
+ // name id
+ if (!lookupTable.containsKey(nr.getNameId()))
{
- isPlatform10 = true;
+ lookupTable.put(nr.getNameId(),
+ new HashMap<Integer, Map<Integer, Map<Integer, String>>>());
}
- String string = data.readString( nr.getStringLength(), charset );
- nr.setString( string );
- int nameID = nr.getNameId();
- if (nameID == NameRecord.NAME_FONT_FAMILY_NAME)
- {
- // prefer 3,1 or 3,0 platform/encoding use 1,0 as fallback
- if (isPlatform310 || (isPlatform10 && fontFamily == null))
- {
- fontFamily = string;
- }
- }
- else if (nameID == NameRecord.NAME_FONT_SUB_FAMILY_NAME)
+ Map<Integer, Map<Integer, Map<Integer, String>>> platformLookup =
+ lookupTable.get(nr.getNameId());
+
+ // platform id
+ if (!platformLookup.containsKey(nr.getPlatformId()))
{
- // prefer 3,1 or 3,0 platform/encoding use 1,0 as fallback
- if (isPlatform310 || (isPlatform10 && fontSubFamily == null))
- {
- fontSubFamily = string;
- }
- }
- else if (nameID == NameRecord.NAME_POSTSCRIPT_NAME)
+ platformLookup.put(nr.getPlatformId(),
+ new HashMap<Integer, Map<Integer, String>>());
+ }
+ Map<Integer, Map<Integer, String>> encodingLookup =
+ platformLookup.get(nr.getPlatformId());
+
+ // encoding id
+ if (!encodingLookup.containsKey(nr.getPlatformEncodingId()))
{
- // prefer 3,1 or 3,0 platform/encoding use 1,0 as fallback
- if (isPlatform310 || (isPlatform10 && psName == null))
- {
- psName = string;
- }
- }
+ encodingLookup.put(nr.getPlatformEncodingId(),
+ new HashMap<Integer, String>());
+ }
+ Map<Integer, String> languageLookup = encodingLookup.get(nr.getPlatformEncodingId());
+
+ // language id / string
+ languageLookup.put(nr.getLanguageId(), nr.getString());
}
+
+ // extract strings of interest
+ fontFamily = getEnglishName(NameRecord.NAME_FONT_FAMILY_NAME);
+ fontSubFamily = getEnglishName(NameRecord.NAME_FONT_SUB_FAMILY_NAME);
+
+ // extract PostScript name, only these two formats are valid
+ psName = getName(NameRecord.NAME_POSTSCRIPT_NAME,
+ NameRecord.PLATFORM_MACINTOSH,
+ NameRecord.ENCODING_MACINTOSH_ROMAN,
+ NameRecord.LANGUGAE_MACINTOSH_ENGLISH);
+ if (psName == null)
+ {
+ psName = getName(NameRecord.NAME_POSTSCRIPT_NAME,
+ NameRecord.PLATFORM_WINDOWS,
+ NameRecord.ENCODING_WINDOWS_UNICODE_BMP,
+ NameRecord.LANGUGAE_WINDOWS_EN_US);
+ }
+
initialized = true;
}
-
+
+ /**
+ * Helper to get English names by best effort.
+ */
+ private String getEnglishName(int nameId)
+ {
+ // Unicode, Full, BMP, 1.1, 1.0
+ for (int i = 4; i <= 0; i--)
+ {
+ String nameUni =
+ getName(nameId,
+ NameRecord.PLATFORM_UNICODE,
+ i,
+ NameRecord.LANGUGAE_UNICODE);
+ if (nameUni != null)
+ {
+ return nameUni;
+ }
+ }
+
+ // Windows, Unicode BMP, EN-US
+ String nameWin =
+ getName(nameId,
+ NameRecord.PLATFORM_WINDOWS,
+ NameRecord.ENCODING_WINDOWS_UNICODE_BMP,
+ NameRecord.LANGUGAE_WINDOWS_EN_US);
+ if (nameWin != null)
+ {
+ return nameWin;
+ }
+
+ // Macintosh, Roman, English
+ String nameMac =
+ getName(nameId,
+ NameRecord.PLATFORM_MACINTOSH,
+ NameRecord.ENCODING_MACINTOSH_ROMAN,
+ NameRecord.LANGUGAE_MACINTOSH_ENGLISH);
+ if (nameMac != null)
+ {
+ return nameMac;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a name from the table, or null it it does not exist.
+ *
+ * @param nameId Name ID from NameRecord constants.
+ * @param platformId Platform ID from NameRecord constants.
+ * @param encodingId Platform Encoding ID from NameRecord constants.
+ * @param languageId Language ID from NameRecord constants.
+ * @return name, or null
+ */
+ public String getName(int nameId, int platformId, int encodingId, int languageId)
+ {
+ Map<Integer, Map<Integer, Map<Integer, String>>> platforms = lookupTable.get(nameId);
+ if (platforms == null)
+ {
+ return null;
+ }
+ Map<Integer, Map<Integer, String>> encodings = platforms.get(platformId);
+ if (encodings == null)
+ {
+ return null;
+ }
+ Map<Integer, String> languages = encodings.get(encodingId);
+ if (languages == null)
+ {
+ return null;
+ }
+ return languages.get(languageId);
+ }
+
/**
* This will get the name records for this naming table.
- *
+ *
* @return A list of NameRecord objects.
*/
public List<NameRecord> getNameRecords()
@@ -135,9 +231,9 @@ public class NamingTable extends TTFTabl
}
/**
- * Returns the font family name.
- *
- * @return the font family name
+ * Returns the font family name, in English.
+ *
+ * @return the font family name, in English
*/
public String getFontFamily()
{
@@ -145,9 +241,9 @@ public class NamingTable extends TTFTabl
}
/**
- * Returns the font sub family name.
- *
- * @return the font sub family name
+ * Returns the font sub family name, in English.
+ *
+ * @return the font sub family name, in English
*/
public String getFontSubFamily()
{
@@ -155,13 +251,12 @@ public class NamingTable extends TTFTabl
}
/**
- * Returns the postscript name.
- *
- * @return the postscript name
+ * Returns the PostScript name.
+ *
+ * @return the PostScript name
*/
- public String getPSName()
+ public String getPostScriptName()
{
return psName;
}
-
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java Sat Aug 30 02:26:57 2014
@@ -24,7 +24,6 @@ import org.apache.fontbox.encoding.Encod
* A table in a true type font.
*
* @author Ben Litchfield (ben@benlitchfield.com)
- *
*/
public class PostScriptTable extends TTFTable
{
@@ -68,8 +67,8 @@ public class PostScriptTable extends TTF
/*
* This TrueType font file contains exactly the 258 glyphs in the standard Macintosh TrueType.
*/
- glyphNames = new String[Encoding.NUMBER_OF_MAC_GLYPHS];
- System.arraycopy(Encoding.MAC_GLYPH_NAMES, 0, glyphNames, 0, Encoding.NUMBER_OF_MAC_GLYPHS);
+ glyphNames = new String[WGL4Names.NUMBER_OF_MAC_GLYPHS];
+ System.arraycopy(WGL4Names.MAC_GLYPH_NAMES, 0, glyphNames, 0, WGL4Names.NUMBER_OF_MAC_GLYPHS);
}
else if (formatType == 2.0f)
{
@@ -89,10 +88,10 @@ public class PostScriptTable extends TTF
}
}
String[] nameArray = null;
- if (maxIndex >= Encoding.NUMBER_OF_MAC_GLYPHS)
+ if (maxIndex >= WGL4Names.NUMBER_OF_MAC_GLYPHS)
{
- nameArray = new String[maxIndex - Encoding.NUMBER_OF_MAC_GLYPHS + 1];
- for (int i = 0; i < maxIndex - Encoding.NUMBER_OF_MAC_GLYPHS + 1; i++)
+ nameArray = new String[maxIndex - WGL4Names.NUMBER_OF_MAC_GLYPHS + 1];
+ for (int i = 0; i < maxIndex - WGL4Names.NUMBER_OF_MAC_GLYPHS + 1; i++)
{
int numberOfChars = data.readUnsignedByte();
nameArray[i] = data.readString(numberOfChars);
@@ -101,13 +100,13 @@ public class PostScriptTable extends TTF
for (int i = 0; i < numGlyphs; i++)
{
int index = glyphNameIndex[i];
- if (index < Encoding.NUMBER_OF_MAC_GLYPHS)
+ if (index < WGL4Names.NUMBER_OF_MAC_GLYPHS)
{
- glyphNames[i] = Encoding.MAC_GLYPH_NAMES[index];
+ glyphNames[i] = WGL4Names.MAC_GLYPH_NAMES[index];
}
- else if (index >= Encoding.NUMBER_OF_MAC_GLYPHS && index <= 32767)
+ else if (index >= WGL4Names.NUMBER_OF_MAC_GLYPHS && index <= 32767)
{
- glyphNames[i] = nameArray[index - Encoding.NUMBER_OF_MAC_GLYPHS];
+ glyphNames[i] = nameArray[index - WGL4Names.NUMBER_OF_MAC_GLYPHS];
}
else
{
@@ -128,7 +127,7 @@ public class PostScriptTable extends TTF
glyphNames = new String[glyphNameIndex.length];
for (int i = 0; i < glyphNames.length; i++)
{
- String name = Encoding.MAC_GLYPH_NAMES[glyphNameIndex[i]];
+ String name = WGL4Names.MAC_GLYPH_NAMES[glyphNameIndex[i]];
if (name != null)
{
glyphNames[i] = name;
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java Sat Aug 30 02:26:57 2014
@@ -69,8 +69,7 @@ public class TTFParser
*/
public TrueTypeFont parseTTF(String ttfFile) throws IOException
{
- RAFDataStream raf = new RAFDataStream(ttfFile, "r");
- return parseTTF(raf);
+ return parseTTF(new File(ttfFile));
}
/**
@@ -82,8 +81,7 @@ public class TTFParser
*/
public TrueTypeFont parseTTF(File ttfFile) throws IOException
{
- RAFDataStream raf = new RAFDataStream(ttfFile, "r");
- return parseTTF(raf);
+ return parseTTF(new RAFDataStream(ttfFile, "r"));
}
/**
@@ -189,7 +187,7 @@ public class TTFParser
}
// check others mandatory tables
- if (!isEmbedded && font.getCMAP() == null)
+ if (!isEmbedded && font.getCmap() == null)
{
throw new IOException("cmap is mandatory");
}
@@ -199,9 +197,9 @@ public class TTFParser
{
TTFTable retval = null;
String tag = raf.readString(4);
- if (tag.equals(CMAPTable.TAG))
+ if (tag.equals(CmapTable.TAG))
{
- retval = new CMAPTable();
+ retval = new CmapTable();
}
else if (tag.equals(GlyphTable.TAG))
{
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java Sat Aug 30 02:26:57 2014
@@ -16,30 +16,31 @@
*/
package org.apache.fontbox.ttf;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.io.IOException;
import java.io.InputStream;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.encoding.Encoding;
+import org.apache.fontbox.util.BoundingBox;
/**
* A TrueType font file.
*
* @author Ben Litchfield
*/
-public class TrueTypeFont
+public class TrueTypeFont implements Type1Equivalent
{
- private final Log log = LogFactory.getLog(TrueTypeFont.class);
-
private float version;
private int numberOfGlyphs = -1;
private int unitsPerEm = -1;
private int[] advanceWidths = null;
private Map<String,TTFTable> tables = new HashMap<String,TTFTable>();
private TTFDataStream data;
+ private Map<String, Integer> postScriptNames;
/**
* Constructor. Clients should use the TTFParser to create a new TrueTypeFont object.
@@ -97,13 +98,23 @@ public class TrueTypeFont
{
return tables.values();
}
+
+ /**
+ * Get all of the tables.
+ *
+ * @return All of the tables.
+ */
+ public Map<String, TTFTable> getTableMap()
+ {
+ return tables;
+ }
/**
* This will get the naming table for the true type font.
*
* @return The naming table.
*/
- public NamingTable getNaming()
+ public synchronized NamingTable getNaming() throws IOException
{
NamingTable naming = (NamingTable)tables.get( NamingTable.TAG );
if (naming != null && !naming.getInitialized())
@@ -118,7 +129,7 @@ public class TrueTypeFont
*
* @return The postscript table.
*/
- public PostScriptTable getPostScript()
+ public synchronized PostScriptTable getPostScript() throws IOException
{
PostScriptTable postscript = (PostScriptTable)tables.get( PostScriptTable.TAG );
if (postscript != null && !postscript.getInitialized())
@@ -133,7 +144,7 @@ public class TrueTypeFont
*
* @return The OS/2 table.
*/
- public OS2WindowsMetricsTable getOS2Windows()
+ public synchronized OS2WindowsMetricsTable getOS2Windows() throws IOException
{
OS2WindowsMetricsTable os2WindowsMetrics = (OS2WindowsMetricsTable)tables.get( OS2WindowsMetricsTable.TAG );
if (os2WindowsMetrics != null && !os2WindowsMetrics.getInitialized())
@@ -148,7 +159,7 @@ public class TrueTypeFont
*
* @return The maxp table.
*/
- public MaximumProfileTable getMaximumProfile()
+ public synchronized MaximumProfileTable getMaximumProfile() throws IOException
{
MaximumProfileTable maximumProfile = (MaximumProfileTable)tables.get( MaximumProfileTable.TAG );
if (maximumProfile != null && !maximumProfile.getInitialized())
@@ -163,7 +174,7 @@ public class TrueTypeFont
*
* @return The head table.
*/
- public HeaderTable getHeader()
+ public synchronized HeaderTable getHeader() throws IOException
{
HeaderTable header = (HeaderTable)tables.get( HeaderTable.TAG );
if (header != null && !header.getInitialized())
@@ -178,7 +189,7 @@ public class TrueTypeFont
*
* @return The hhea table.
*/
- public HorizontalHeaderTable getHorizontalHeader()
+ public synchronized HorizontalHeaderTable getHorizontalHeader() throws IOException
{
HorizontalHeaderTable horizontalHeader = (HorizontalHeaderTable)tables.get( HorizontalHeaderTable.TAG );
if (horizontalHeader != null && !horizontalHeader.getInitialized())
@@ -193,7 +204,7 @@ public class TrueTypeFont
*
* @return The hmtx table.
*/
- public HorizontalMetricsTable getHorizontalMetrics()
+ public synchronized HorizontalMetricsTable getHorizontalMetrics() throws IOException
{
HorizontalMetricsTable horizontalMetrics = (HorizontalMetricsTable)tables.get( HorizontalMetricsTable.TAG );
if (horizontalMetrics != null && !horizontalMetrics.getInitialized())
@@ -208,7 +219,7 @@ public class TrueTypeFont
*
* @return The loca table.
*/
- public IndexToLocationTable getIndexToLocation()
+ public synchronized IndexToLocationTable getIndexToLocation() throws IOException
{
IndexToLocationTable indexToLocation = (IndexToLocationTable)tables.get( IndexToLocationTable.TAG );
if (indexToLocation != null && !indexToLocation.getInitialized())
@@ -223,7 +234,7 @@ public class TrueTypeFont
*
* @return The glyf table.
*/
- public GlyphTable getGlyph()
+ public synchronized GlyphTable getGlyph() throws IOException
{
GlyphTable glyph = (GlyphTable)tables.get( GlyphTable.TAG );
if (glyph != null && !glyph.getInitialized())
@@ -234,13 +245,13 @@ public class TrueTypeFont
}
/**
- * Get the cmap table for this TTF.
+ * Get the "cmap" table for this TTF.
*
- * @return The cmap table.
+ * @return The "cmap" table.
*/
- public CMAPTable getCMAP()
+ public synchronized CmapTable getCmap() throws IOException
{
- CMAPTable cmap = (CMAPTable)tables.get( CMAPTable.TAG );
+ CmapTable cmap = (CmapTable)tables.get( CmapTable.TAG );
if (cmap != null && !cmap.getInitialized())
{
readTable(cmap);
@@ -267,21 +278,14 @@ public class TrueTypeFont
*
* @param table the table to be initialized
*/
- void readTable(TTFTable table)
+ void readTable(TTFTable table) throws IOException
{
- try
- {
- // save current position
- long currentPosition = data.getCurrentPosition();
- data.seek(table.getOffset());
- table.read(this, data);
- // restore current position
- data.seek(currentPosition);
- }
- catch (IOException exception)
- {
- log.error("An error occured when reading table " + table.getTag(), exception);
- }
+ // save current position
+ long currentPosition = data.getCurrentPosition();
+ data.seek(table.getOffset());
+ table.read(this, data);
+ // restore current position
+ data.seek(currentPosition);
}
/**
@@ -289,7 +293,7 @@ public class TrueTypeFont
*
* @return the number of glyphs
*/
- public int getNumberOfGlyphs()
+ public int getNumberOfGlyphs() throws IOException
{
if (numberOfGlyphs == -1)
{
@@ -312,7 +316,7 @@ public class TrueTypeFont
*
* @return units per EM
*/
- public int getUnitsPerEm()
+ public int getUnitsPerEm() throws IOException
{
if (unitsPerEm == -1)
{
@@ -331,12 +335,12 @@ public class TrueTypeFont
}
/**
- * Returns the width for the given glyph code.
+ * Returns the width for the given GID.
*
- * @param code the glyph code
+ * @param gid the GID
* @return the width
*/
- public int getAdvanceWidth(int code)
+ public int getAdvanceWidth(int gid) throws IOException
{
if (advanceWidths == null)
{
@@ -351,9 +355,9 @@ public class TrueTypeFont
advanceWidths = new int[]{250};
}
}
- if (advanceWidths.length > code)
+ if (advanceWidths.length > gid)
{
- return advanceWidths[code];
+ return advanceWidths[gid];
}
else
{
@@ -362,4 +366,144 @@ public class TrueTypeFont
return advanceWidths[advanceWidths.length-1];
}
}
+
+ @Override
+ public String getFullName() throws IOException
+ {
+ if (getNaming() != null)
+ {
+ return getNaming().getPostScriptName();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private synchronized void readPostScriptNames() throws IOException
+ {
+ if (postScriptNames == null)
+ {
+ postScriptNames = new HashMap<String, Integer>();
+ if (getPostScript() != null)
+ {
+ String[] names = getPostScript().getGlyphNames();
+ if (names != null)
+ {
+ for (int i = 0; i < names.length; i++)
+ {
+ postScriptNames.put(names[i], i);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the GID for the given PostScript name, if the "post" table is present.
+ */
+ public int nameToGID(String name) throws IOException
+ {
+ readPostScriptNames();
+
+ GlyphData[] glyphs = getGlyph().getGlyphs();
+ Integer gid = postScriptNames.get(name);
+ if (gid == null || gid < 0 || gid >= glyphs.length)
+ {
+ return 0;
+ }
+ return gid;
+ }
+
+ @Override
+ public GeneralPath getPath(String name) throws IOException
+ {
+ readPostScriptNames();
+
+ GlyphData[] glyphs = getGlyph().getGlyphs();
+ Integer gid = postScriptNames.get(name);
+ if (gid == null || gid < 0 || gid >= glyphs.length)
+ {
+ gid = 0;
+ }
+
+ // some glyphs have no outlines (e.g. space, table, newline)
+ if (glyphs[gid] == null)
+ {
+ return new GeneralPath();
+ }
+ else
+ {
+ GeneralPath path = glyphs[gid].getPath();
+
+ // scale to 1000upem, per PostScript convention
+ float scale = 1000f / getUnitsPerEm();
+ AffineTransform atScale = AffineTransform.getScaleInstance(scale, scale);
+ path.transform(atScale);
+
+ return path;
+ }
+ }
+
+ @Override
+ public float getWidth(String name) throws IOException
+ {
+ readPostScriptNames();
+
+ Integer gid = postScriptNames.get(name);
+ int width = getAdvanceWidth(gid);
+ int unitsPerEM = getUnitsPerEm();
+ if (unitsPerEM != 1000)
+ {
+ width *= 1000f / unitsPerEM;
+ }
+ return width;
+ }
+
+ @Override
+ public boolean hasGlyph(String name) throws IOException
+ {
+ readPostScriptNames();
+
+ Integer gid = postScriptNames.get(name);
+ GlyphData[] glyphs = getGlyph().getGlyphs();
+ return !(gid == null || gid < 0 || gid >= glyphs.length);
+ }
+
+ @Override
+ public Encoding getEncoding()
+ {
+ return null;
+ }
+
+ @Override
+ public BoundingBox getFontBBox() throws IOException
+ {
+ short xMin = getHeader().getXMin();
+ short xMax = getHeader().getXMax();
+ short yMin = getHeader().getYMin();
+ short yMax = getHeader().getYMax();
+ float scale = 1000f / getUnitsPerEm();
+ return new BoundingBox(xMin * scale, yMin * scale, xMax * scale, yMax * scale);
+ }
+
+ @Override
+ public String toString()
+ {
+ try
+ {
+ if (getNaming() != null)
+ {
+ return getNaming().getPostScriptName();
+ }
+ else
+ {
+ return "(null)";
+ }
+ }
+ catch (IOException e)
+ {
+ return "(null - " + e.getMessage() + ")";
+ }
+ }
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java Sat Aug 30 02:26:57 2014
@@ -21,23 +21,25 @@ import org.apache.fontbox.cff.Type1CharS
import org.apache.fontbox.cff.Type1CharStringParser;
import org.apache.fontbox.encoding.Encoding;
import org.apache.fontbox.pfb.PfbParser;
+import org.apache.fontbox.ttf.Type1Equivalent;
+import org.apache.fontbox.util.BoundingBox;
+import java.awt.geom.GeneralPath;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
- * Represents an Adobe Type 1 (.pfb) font.
+ * Represents an Adobe Type 1 (.pfb) font. Thread safe.
*
* @author John Hewson
*/
-public final class Type1Font implements Type1CharStringReader
+public final class Type1Font implements Type1CharStringReader, Type1Equivalent
{
/**
* Constructs a new Type1Font object from a .pfb stream.
@@ -109,8 +111,8 @@ public final class Type1Font implements
final Map<String, byte[]> charstrings = new LinkedHashMap<String, byte[]>();
// private caches
- private final Map<String, Type1CharString> charStringCache = new HashMap<String, Type1CharString>();
- private Collection<Mapping> mappings;
+ private final Map<String, Type1CharString> charStringCache =
+ new ConcurrentHashMap<String, Type1CharString>();
/**
* Constructs a new Type1Font, called by Type1Parser.
@@ -139,112 +141,41 @@ public final class Type1Font implements
return Collections.unmodifiableMap(charstrings);
}
- /**
- * {@inheritDoc}
- */
- public Type1CharString getType1CharString(String name) throws IOException
+ @Override
+ public GeneralPath getPath(String name) throws IOException
{
- Type1CharString type1 = charStringCache.get(name);
- if (type1 == null)
- {
- Type1CharStringParser parser = new Type1CharStringParser(fontName, name);
- List<Object> sequence = parser.parse(charstrings.get(name), subrs);
- type1 = new Type1CharString(this, fontName, name, sequence);
- charStringCache.put(name, type1);
- }
- return type1;
+ return getType1CharString(name).getPath();
}
- /**
- * Get the mappings for the font as Type1Mapping.
- *
- * @return the Type1Mapping
- */
- public Collection<? extends Type1Mapping> getType1Mappings()
+ @Override
+ public float getWidth(String name) throws IOException
{
- return getMappings();
+ return getType1CharString(name).getWidth();
}
- /**
- * Get the mapping (code/charname/bytes) for this font.
- *
- * @return mappings for character codes
- */
- public Collection<Type1Font.Mapping> getMappings()
+ @Override
+ public boolean hasGlyph(String name)
{
- if (mappings == null)
- {
- mappings = new ArrayList<Mapping>();
- for (String name : getCharStringsDict().keySet())
- {
- Integer code = encoding.getCode(name);
- if (code == null)
- {
- code = 0; // .notdef
- }
- Mapping mapping = new Mapping();
- mapping.setCode(code);
- mapping.setName(name);
- mapping.setBytes(getCharStringsDict().get(name));
- mappings.add(mapping);
- }
- mappings = Collections.unmodifiableCollection(mappings);
- }
- return mappings;
+ return charstrings.get(name) != null;
}
- public class Mapping implements Type1Mapping
+ @Override
+ public Type1CharString getType1CharString(String name) throws IOException
{
- private int mappedCode;
- private String mappedName;
- private byte[] mappedBytes;
-
- /**
- * {@inheritDoc}
- */
- public Type1CharString getType1CharString() throws IOException
- {
- return Type1Font.this.getType1CharString(mappedName);
- }
-
- /**
- * {@inheritDoc}
- */
- public int getCode()
- {
- return mappedCode;
- }
-
- private void setCode(int code)
- {
- mappedCode = code;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getName()
- {
- return mappedName;
- }
-
- private void setName(String name)
- {
- this.mappedName = name;
- }
-
- /**
- * {@inheritDoc}
- */
- public byte[] getBytes()
- {
- return mappedBytes;
- }
-
- private void setBytes(byte[] bytes)
+ Type1CharString type1 = charStringCache.get(name);
+ if (type1 == null)
{
- this.mappedBytes = bytes;
+ byte[] bytes = charstrings.get(name);
+ if (bytes == null)
+ {
+ bytes = charstrings.get(".notdef");
+ }
+ Type1CharStringParser parser = new Type1CharStringParser(fontName, name);
+ List<Object> sequence = parser.parse(bytes, subrs);
+ type1 = new Type1CharString(this, fontName, name, sequence);
+ charStringCache.put(name, type1);
}
+ return type1;
}
// font dictionary
@@ -303,9 +234,9 @@ public final class Type1Font implements
*
* @return the font bounding box
*/
- public List<Number> getFontBBox()
+ public BoundingBox getFontBBox()
{
- return Collections.unmodifiableList(fontBBox);
+ return new BoundingBox(fontBBox);
}
/**
@@ -365,6 +296,7 @@ public final class Type1Font implements
*
* @return the full name
*/
+ @Override
public String getFullName()
{
return fullName;
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java Sat Aug 30 02:26:57 2014
@@ -17,6 +17,8 @@
package org.apache.fontbox.util;
+import java.util.List;
+
/**
* This is an implementation of a bounding box. This was originally written for the
* AMF parser.
@@ -52,6 +54,20 @@ public class BoundingBox
upperRightX = maxX;
upperRightY = maxY;
}
+
+ /**
+ * Constructor.
+ *
+ * @param numbers list of four numbers
+ */
+ public BoundingBox(List<Number> numbers)
+ {
+ lowerLeftX = numbers.get(0).floatValue();
+ lowerLeftY = numbers.get(1).floatValue();
+ upperRightX = numbers.get(2).floatValue();
+ upperRightY = numbers.get(3).floatValue();
+ }
+
/**
* Getter for property lowerLeftX.
*