blob: b076ce2242b7538e38035fb3443d131e92459776 [file]
Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java (revision 1546564)
+++ fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java (working copy)
@@ -36,7 +36,7 @@
import org.apache.fontbox.cff.encoding.CFFStandardEncoding;
/**
- * This class represents a parser for a CFF font.
+ * This class represents a parser for a CFF font.
* @author Villu Ruusmann
* @version $Revision: 1.0 $
*/
@@ -107,7 +107,11 @@
{
input.setPosition(0);
}
+ return parse(input);
+ }
+ public List<CFFFont> parse(CFFDataInput input) throws IOException {
+ this.input = input;
header = readHeader(input);
nameIndex = readIndexData(input);
topDictIndex = readIndexData(input);
@@ -119,6 +123,7 @@
{
CFFFont font = parseFont(i);
font.setGlobalSubrIndex(globalSubrIndex);
+ font.constructMappings();
fonts.add(font);
}
return fonts;
@@ -145,7 +150,7 @@
return cffHeader;
}
- private static IndexData readIndexData(CFFDataInput input) throws IOException
+ public static IndexData readIndexData(CFFDataInput input) throws IOException
{
int count = input.readCard16();
IndexData index = new IndexData(count);
@@ -179,7 +184,8 @@
return dict;
}
- private static DictData.Entry readEntry(CFFDataInput input) throws IOException
+ private static DictData.Entry readEntry(CFFDataInput input)
+ throws IOException
{
DictData.Entry entry = new DictData.Entry();
while (true)
@@ -211,13 +217,15 @@
return entry;
}
- private static CFFOperator readOperator(CFFDataInput input, int b0) throws IOException
+ private static CFFOperator readOperator(CFFDataInput input, int b0)
+ throws IOException
{
CFFOperator.Key key = readOperatorKey(input, b0);
return CFFOperator.getOperator(key);
}
- private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0) throws IOException
+ private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0)
+ throws IOException
{
if (b0 == 12)
{
@@ -227,7 +235,8 @@
return new CFFOperator.Key(b0);
}
- private static Integer readIntegerNumber(CFFDataInput input, int b0) throws IOException
+ private static Integer readIntegerNumber(CFFDataInput input, int b0)
+ throws IOException
{
if (b0 == 28)
{
@@ -263,7 +272,8 @@
}
}
- private static Double readRealNumber(CFFDataInput input, int b0) throws IOException
+ private static Double readRealNumber(CFFDataInput input, int b0)
+ throws IOException
{
StringBuffer sb = new StringBuffer();
boolean done = false;
@@ -446,9 +456,9 @@
throw new IOException("FDArray is missing for a CIDKeyed Font.");
}
- int fontDictOffset = fdArrayEntry.getNumber(0).intValue();
- input.setPosition(fontDictOffset);
- IndexData fdIndex = readIndexData(input);
+ int fontDictOffset = fdArrayEntry.getNumber(0).intValue();
+ input.setPosition(fontDictOffset);
+ IndexData fdIndex = readIndexData(input);
List<Map<String, Object>> privateDictionaries = new LinkedList<Map<String, Object>>();
List<Map<String, Object>> fontDictionaries = new LinkedList<Map<String, Object>>();
@@ -577,8 +587,8 @@
{
return CFFStandardString.getName(index);
}
- if (index - 391 <= stringIndex.getCount())
- {
+ if (index - 391 < stringIndex.getCount())
+ {
DataInput dataInput = new DataInput(stringIndex.getBytes(index - 391));
return dataInput.getString();
}
@@ -620,7 +630,8 @@
return entry != null ? entry.getArray() : defaultValue;
}
- private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids) throws IOException
+ private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids)
+ throws IOException
{
int format = dataInput.readCard8();
int baseFormat = format & 0x7f;
@@ -639,7 +650,8 @@
}
}
- private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format, int[] gids) throws IOException
+ private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format,
+ int[] gids) throws IOException
{
Format0Encoding encoding = new Format0Encoding();
encoding.format = format;
@@ -657,7 +669,8 @@
return encoding;
}
- private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format, int[] gids) throws IOException
+ private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format,
+ int[] gids) throws IOException
{
Format1Encoding encoding = new Format1Encoding();
encoding.format = format;
@@ -683,7 +696,8 @@
return encoding;
}
- private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding) throws IOException
+ private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding)
+ throws IOException
{
encoding.nSups = dataInput.readCard8();
encoding.supplement = new EmbeddedEncoding.Supplement[encoding.nSups];
@@ -738,15 +752,14 @@
fdselect.fds = new int[nGlyphs];
for (int i = 0; i < fdselect.fds.length; i++)
{
- fdselect.fds[i] = dataInput.readCard8();
-
+ fdselect.fds[i] = dataInput.readCard8();
}
return fdselect;
}
/**
* Read the Format 3 of the FDSelect data structure.
- *
+ *
* @param dataInput
* @param format
* @param nGlyphs
@@ -768,7 +781,6 @@
r3.first = dataInput.readCard16();
r3.fd = dataInput.readCard8();
fdselect.range3[i] = r3;
-
}
fdselect.sentinel = dataInput.readCard16();
@@ -902,7 +914,8 @@
}
}
- private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs) throws IOException
+ private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs)
+ throws IOException
{
int format = dataInput.readCard8();
if (format == 0)
@@ -923,7 +936,8 @@
}
}
- private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException
+ private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format,
+ int nGlyphs) throws IOException
{
Format0Charset charset = new Format0Charset();
charset.format = format;
@@ -936,7 +950,8 @@
return charset;
}
- private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException
+ private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format,
+ int nGlyphs) throws IOException
{
Format1Charset charset = new Format1Charset();
charset.format = format;
@@ -957,7 +972,8 @@
return charset;
}
- private Format2Charset readFormat2Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException
+ private Format2Charset readFormat2Charset(CFFDataInput dataInput, int format,
+ int nGlyphs) throws IOException
{
Format2Charset charset = new Format2Charset();
charset.format = format;
@@ -981,7 +997,7 @@
}
/**
- * Inner class holding the header of a CFF font.
+ * Inner class holding the header of a CFF font.
*/
private static class Header
{
@@ -999,7 +1015,7 @@
}
/**
- * Inner class holding the DictData of a CFF font.
+ * Inner class holding the DictData of a CFF font.
*/
private static class DictData
{
@@ -1030,7 +1046,7 @@
}
/**
- * {@inheritDoc}
+ * {@inheritDoc}
*/
public String toString()
{
@@ -1038,7 +1054,7 @@
}
/**
- * Inner class holding an operand of a CFF font.
+ * Inner class holding an operand of a CFF font.
*/
private static class Entry
{
@@ -1100,7 +1116,7 @@
}
/**
- * Inner class representing an embedded CFF encoding.
+ * Inner class representing an embedded CFF encoding.
*/
abstract static class EmbeddedEncoding extends CFFEncoding
{
@@ -1124,7 +1140,7 @@
}
/**
- * Inner class representing a supplement for an encoding.
+ * Inner class representing a supplement for an encoding.
*/
static class Supplement
{
@@ -1150,7 +1166,7 @@
}
/**
- * Inner class representing a Format0 encoding.
+ * Inner class representing a Format0 encoding.
*/
private static class Format0Encoding extends EmbeddedEncoding
{
@@ -1167,7 +1183,7 @@
}
/**
- * Inner class representing a Format1 encoding.
+ * Inner class representing a Format1 encoding.
*/
private static class Format1Encoding extends EmbeddedEncoding
{
@@ -1183,7 +1199,7 @@
}
/**
- * Inner class representing a range of an encoding.
+ * Inner class representing a range of an encoding.
*/
private static class Range1
{
@@ -1193,13 +1209,20 @@
@Override
public String toString()
{
- return getClass().getName() + "[first=" + first + ", nLeft=" + nLeft + "]";
+ return getClass().getName() + "[first=" + first + ", nLeft="
+ + nLeft + "]";
}
+
+ @Override
+ public boolean equals(Object obj) {
+ Range1 r = (Range1)obj;
+ return (first == r.first && nLeft == r.nLeft);
+ }
}
}
/**
- * Inner class representing an embedded CFF charset.
+ * Inner class representing an embedded CFF charset.
*/
abstract static class EmbeddedCharset extends CFFCharset
{
@@ -1211,7 +1234,7 @@
}
/**
- * Inner class representing a Format0 charset.
+ * Inner class representing a Format0 charset.
*/
private static class Format0Charset extends EmbeddedCharset
{
@@ -1226,7 +1249,7 @@
}
/**
- * Inner class representing a Format1 charset.
+ * Inner class representing a Format1 charset.
*/
private static class Format1Charset extends EmbeddedCharset
{
@@ -1240,7 +1263,7 @@
}
/**
- * Inner class representing a range of a charset.
+ * Inner class representing a range of a charset.
*/
private static class Range1
{
@@ -1256,7 +1279,7 @@
}
/**
- * Inner class representing a Format2 charset.
+ * Inner class representing a Format2 charset.
*/
private static class Format2Charset extends EmbeddedCharset
{
@@ -1270,7 +1293,7 @@
}
/**
- * Inner class representing a range of a charset.
+ * Inner class representing a range of a charset.
*/
private static class Range2
{
@@ -1284,4 +1307,8 @@
}
}
}
+
+ public IndexData getStringIndex() {
+ return stringIndex;
+ }
}
Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (revision 1546564)
+++ fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (working copy)
@@ -31,7 +31,7 @@
/**
* This class represents a CFF/Type2 Font.
- *
+ *
* @author Villu Ruusmann
* @version $Revision$
*/
@@ -44,6 +44,8 @@
private CFFEncoding fontEncoding = null;
private CFFCharset fontCharset = null;
private Map<String, byte[]> charStringsDict = new LinkedHashMap<String, byte[]>();
+ Map<Integer, Mapping> sidMappings = null;
+ ArrayList<Mapping> gidMappings = null;
private IndexData globalSubrIndex = null;
private IndexData localSubrIndex = null;
@@ -97,6 +99,7 @@
topDict.put(name, value);
}
}
+
/**
* Returns the top dictionary.
* @return the dictionary
@@ -107,7 +110,7 @@
}
/**
- * Adds the given key/value pair to the private dictionary.
+ * Adds the given key/value pair to the private dictionary.
* @param name the given key
* @param value the given value
*/
@@ -118,7 +121,8 @@
privateDict.put(name, value);
}
}
- /**
+
+ /**
* Returns the private dictionary.
* @return the dictionary
*/
@@ -127,14 +131,60 @@
return privateDict;
}
+ /**
+ * Returns a mapping for a given GID
+ * @param GID The given GID
+ * @return The found mapping
+ */
+ public Mapping getMapping(int GID) {
+ return sidMappings.get(GID);
+ }
+
/**
- * Get the mapping (code/SID/charname/bytes) for this font.
- * @return mappings for codes < 256 and for codes > = 256
- */
- public Collection<Mapping> getMappings()
+ * Get the mapping (code/SID/charname/bytes) for this font.
+ * @return mappings for codes < 256 and for codes > = 256
+ */
+ public Collection<Mapping> getMappings() {
+ constructMappings();
+ return sidMappings.values();
+ }
+
+ /**
+ * Gets the GID mappings list.
+ */
+ public ArrayList<Mapping> getGIDMappings() {
+ return gidMappings;
+ }
+
+ private void constructGIDMap() {
+ gidMappings = new ArrayList<Mapping>();
+ Mapping notdef = new Mapping();
+ notdef.setName(".notdef");
+ gidMappings.add(notdef);
+ for (CFFCharset.Entry entry : fontCharset.getEntries())
+ {
+ String name = entry.getName();
+ byte[] bytes = this.charStringsDict.get(name);
+ if (bytes == null)
+ {
+ continue;
+ }
+ Mapping mapping = new Mapping();
+ mapping.setSID(entry.getSID());
+ mapping.setName(name);
+ mapping.setBytes(bytes);
+ gidMappings.add(mapping);
+ }
+ }
+
+ /**
+ * Construct the mappings.
+ */
+ public void constructMappings()
{
- List<Mapping> mappings = new ArrayList<Mapping>();
- Set<String> mappedNames = new HashSet<String>();
+ constructGIDMap();
+ sidMappings = new LinkedHashMap<Integer, Mapping>();
+ Set<String> mappedNames = new HashSet<String>();
for (CFFEncoding.Entry entry : fontEncoding.getEntries())
{
String charName = fontCharset.getName(entry.getSID());
@@ -153,7 +203,7 @@
mapping.setSID(entry.getSID());
mapping.setName(charName);
mapping.setBytes(bytes);
- mappings.add(mapping);
+ sidMappings.put(mapping.getSID(), mapping);
mappedNames.add(charName);
}
if (fontEncoding instanceof CFFParser.EmbeddedEncoding)
@@ -177,7 +227,7 @@
mapping.setSID(supplement.getGlyph());
mapping.setName(charName);
mapping.setBytes(bytes);
- mappings.add(mapping);
+ sidMappings.put(mapping.getSID(), mapping);
mappedNames.add(charName);
}
}
@@ -185,7 +235,7 @@
int code = 256;
for (CFFCharset.Entry entry : fontCharset.getEntries())
{
- String name = entry.getName();
+ String name = entry.getName();
if (mappedNames.contains(name))
{
continue;
@@ -201,11 +251,10 @@
mapping.setName(name);
mapping.setBytes(bytes);
- mappings.add(mapping);
+ sidMappings.put(mapping.getSID(), mapping);
mappedNames.add(name);
}
- return mappings;
}
/**
@@ -215,34 +264,43 @@
* @return -1 if the SID is missing from the Font.
* @throws IOException
*/
- public int getWidth(int SID) throws IOException {
- int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number)privateDict.get("nominalWidthX")).intValue() : 0;
- int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number)privateDict.get("defaultWidthX")).intValue() : 1000 ;
-
- for (Mapping m : getMappings() ){
- if (m.getSID() == SID) {
+ public int getWidth(int SID) throws IOException {
+ int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number) privateDict.get("nominalWidthX")).intValue() : 0;
+ int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number) privateDict.get("defaultWidthX")).intValue() : 1000;
+ Mapping m = sidMappings.get(SID);
+ if (m != null) {
+ CharStringRenderer csr = getRendererForMapping(m);
+ // ---- If the CharString has a Width nominalWidthX must be added,
+ // otherwise it is the default width.
+ return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
+ }
- CharStringRenderer csr = null;
- if (((Number)getProperty("CharstringType")).intValue() == 2 ) {
- List<Object> lSeq = m.toType2Sequence();
- csr = new CharStringRenderer(false);
- csr.render(lSeq);
- } else {
- List<Object> lSeq = m.toType1Sequence();
- csr = new CharStringRenderer();
- csr.render(lSeq);
- }
+ // ---- SID Width not found, return the nodef width
+ return getNotDefWidth(defaultWidth, nominalWidth);
+ }
- // ---- If the CharString has a Width nominalWidthX must be added,
- // otherwise it is the default width.
- return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
- }
- }
+ private CharStringRenderer getRendererForMapping(Mapping m) throws IOException {
+ CharStringRenderer csr = null;
+ if (((Number) getProperty("CharstringType")).intValue() == 2) {
+ List<Object> lSeq = m.toType2Sequence();
+ csr = new CharStringRenderer(false);
+ csr.render(lSeq);
+ } else {
+ List<Object> lSeq = m.toType1Sequence();
+ csr = new CharStringRenderer();
+ csr.render(lSeq);
+ }
+ return csr;
+ }
- // ---- SID Width not found, return the nodef width
- return getNotDefWidth(defaultWidth, nominalWidth);
- }
-
+ /**
+ * Returns the witdth of the .notdef character.
+ *
+ * @param defaultWidth default width
+ * @param nominalWidth nominal width
+ * @return the calculated width for the .notdef character
+ * @throws IOException if something went wrong
+ */
protected int getNotDefWidth(int defaultWidth, int nominalWidth) throws IOException {
CharStringRenderer csr;
byte[] glyphDesc = this.getCharStringsDict().get(".notdef");
@@ -260,6 +318,36 @@
return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
}
+ /**
+ * Return the Width value of the given Glyph identifier
+ *
+ * @param SID
+ * @return -1 if the SID is missing from the Font.
+ * @throws IOException
+ */
+ public int[] getBoundingBox(int SID) throws IOException {
+ Mapping m = sidMappings.get(SID);
+ if (m != null) {
+ CharStringRenderer csr = getRendererForMapping(m);
+ return csr.getBounds();
+ }
+ // ---- SID Width not found, return the nodef width
+ return new int[4];
+ }
+
+ /**
+ * Gets the name of a character from the given SID
+ * @param SID The given SID
+ * @return The name of the found character
+ */
+ public String getNameOfCharFromCode(int SID) {
+ if (sidMappings.get(SID) != null) {
+ return sidMappings.get(SID).getName();
+ } else {
+ return "";
+ }
+ }
+
/**
* Returns the CFFEncoding of the font.
* @return the encoding
@@ -336,50 +424,51 @@
+ charStringsDict + "]";
}
+ /**
+ * Sets the global subroutine index data.
+ * @param globalSubrIndex the IndexData object containing the global subroutines
+ */
+ public void setGlobalSubrIndex(IndexData globalSubrIndexValue) {
+ globalSubrIndex = globalSubrIndexValue;
+ }
- /**
- * Sets the global subroutine index data.
- * @param globalSubrIndex the IndexData object containing the global subroutines
- */
- public void setGlobalSubrIndex(IndexData globalSubrIndex) {
- this.globalSubrIndex = globalSubrIndex;
- }
+ /**
+ * Returns the global subroutine index data.
+ * @return the dictionary
+ */
+ public IndexData getGlobalSubrIndex()
+ {
+ return globalSubrIndex;
+ }
- /**
- * Returns the global subroutine index data.
- * @return the dictionary
- */
- public IndexData getGlobalSubrIndex() {
- return globalSubrIndex;
- }
+ /**
+ * Returns the local subroutine index data.
+ * @return the dictionary
+ */
+ public IndexData getLocalSubrIndex()
+ {
+ return localSubrIndex;
+ }
- /**
- * Returns the local subroutine index data.
- * @return the dictionary
- */
- public IndexData getLocalSubrIndex() {
- return localSubrIndex;
- }
+ /**
+ * Sets the local subroutine index data.
+ * @param localSubrIndexValue the IndexData object containing the local subroutines
+ */
+ public void setLocalSubrIndex(IndexData localSubrIndexValue) {
+ localSubrIndex = localSubrIndexValue;
+ }
- /**
- * Sets the local subroutine index data.
- * @param localSubrIndex the IndexData object containing the local subroutines
- */
- public void setLocalSubrIndex(IndexData localSubrIndex) {
- this.localSubrIndex = localSubrIndex;
- }
+ /**
+ * This class is used for the font mapping.
+ *
+ */
+ public class Mapping
+ {
+ private int mappedCode;
+ private int mappedSID;
+ private String mappedName;
+ private byte[] mappedBytes;
- /**
- * This class is used for the font mapping.
- *
- */
- public class Mapping
- {
- private int mappedCode;
- private int mappedSID;
- private String mappedName;
- private byte[] mappedBytes;
-
/**
* Converts the mapping into a Type1-sequence.
* @return the Type1-sequence
@@ -458,4 +547,4 @@
this.mappedBytes = bytes;
}
}
-}
\ No newline at end of file
+}