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 [4/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/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java Sat Aug 30 02:26:57 2014
@@ -17,47 +17,185 @@
package org.apache.pdfbox.pdmodel.font;
import java.io.IOException;
-import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+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.COSName;
import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.io.IOUtils;
-import org.apache.pdfbox.pdmodel.common.PDRectangle;
-import org.apache.pdfbox.util.ResourceLoader;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.Vector;
/**
- * A CIDFont.
+ * A CIDFont. A CIDFont is a PDF object that contains information about a CIDFont program. Although
+ * its Type value is Font, a CIDFont is not actually a font.
*
* @author Ben Litchfield
*/
-public abstract class PDCIDFont extends PDFont
+public abstract class PDCIDFont implements COSObjectable
{
- private static final Log LOG = LogFactory.getLog(PDCIDFont.class);
+ protected final PDType0Font parent;
- private PDType0Font parent;
- private Map<Integer, Float> widthCache;
- private long defaultWidth;
+ private Map<Integer, Float> widths;
+ private float defaultWidth;
+
+ private Map<Integer, Float> verticalDisplacementY = new HashMap<Integer, Float>(); // w1y
+ private Map<Integer, Vector> positionVectors = new HashMap<Integer, Vector>(); // v
+ private float[] dw2;
+
+ protected final COSDictionary dict;
+ private PDFontDescriptor fontDescriptor;
/**
* Constructor.
*
* @param fontDictionary The font dictionary according to the PDF specification.
*/
- protected PDCIDFont(COSDictionary fontDictionary, PDType0Font parent)
+ protected PDCIDFont(COSDictionary fontDictionary, PDType0Font parent) throws IOException
{
- super(fontDictionary);
+ this.dict = fontDictionary;
this.parent = parent;
- extractWidths();
+ readWidths();
+ readVerticalDisplacements();
+ }
+
+ private void readWidths()
+ {
+ widths = new HashMap<Integer, Float>();
+ COSArray widths = (COSArray) dict.getDictionaryObject(COSName.W);
+ if (widths != null)
+ {
+ int size = widths.size();
+ int counter = 0;
+ while (counter < size)
+ {
+ COSNumber firstCode = (COSNumber) widths.getObject(counter++);
+ COSBase next = widths.getObject(counter++);
+ if (next instanceof COSArray)
+ {
+ COSArray array = (COSArray) next;
+ int startRange = firstCode.intValue();
+ int arraySize = array.size();
+ for (int i = 0; i < arraySize; i++)
+ {
+ COSNumber width = (COSNumber) array.get(i);
+ this.widths.put(startRange + i, width.floatValue());
+ }
+ }
+ else
+ {
+ COSNumber secondCode = (COSNumber) next;
+ COSNumber rangeWidth = (COSNumber) widths.getObject(counter++);
+ int startRange = firstCode.intValue();
+ int endRange = secondCode.intValue();
+ float width = rangeWidth.floatValue();
+ for (int i = startRange; i <= endRange; i++)
+ {
+ this.widths.put(i, width);
+ }
+ }
+ }
+ }
+
+ }
+
+ private void readVerticalDisplacements()
+ {
+ // default position vector and vertical displacement vector
+ COSArray cosDW2 = (COSArray) dict.getDictionaryObject(COSName.DW2);
+ if (cosDW2 != null)
+ {
+ dw2 = new float[2];
+ dw2[0] = ((COSNumber)cosDW2.get(0)).floatValue();
+ dw2[1] = ((COSNumber)cosDW2.get(1)).floatValue();
+ }
+ else
+ {
+ dw2 = new float[] { 880, -1000 };
+ }
+
+ // vertical metrics for individual CIDs.
+ COSArray w2 = (COSArray) dict.getDictionaryObject(COSName.W2);
+ if (w2 != null)
+ {
+ for (int i = 0; i < w2.size(); i++)
+ {
+ COSNumber c = (COSNumber)w2.get(i);
+ COSBase next = w2.get(++i);
+ if (next instanceof COSArray)
+ {
+ COSArray array = (COSArray)next;
+ for (int j = 0; j < array.size(); j++)
+ {
+ int cid = c.intValue() + j;
+ COSNumber w1y = (COSNumber) array.get(j);
+ COSNumber v1x = (COSNumber) array.get(++j);
+ COSNumber v1y = (COSNumber) array.get(++j);
+ verticalDisplacementY.put(cid, w1y.floatValue());
+ positionVectors.put(cid, new Vector(v1x.floatValue(), v1y.floatValue()));
+ }
+ }
+ else
+ {
+ int first = c.intValue();
+ int last = ((COSNumber) next).intValue();
+ COSNumber w1y = (COSNumber) w2.get(++i);
+ COSNumber v1x = (COSNumber) w2.get(++i);
+ COSNumber v1y = (COSNumber) w2.get(++i);
+ for (int cid = first; cid <= last; cid++)
+ {
+ verticalDisplacementY.put(cid, w1y.floatValue());
+ positionVectors.put(cid, new Vector(v1x.floatValue(), v1y.floatValue()));
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public COSDictionary getCOSObject()
+ {
+ return dict;
+ }
+
+ /**
+ * The PostScript name of the font.
+ *
+ * @return The postscript name of the font.
+ */
+ public String getBaseFont()
+ {
+ return dict.getNameAsString(COSName.BASE_FONT);
}
/**
+ * This will get the font descriptor for this font. A font descriptor is required for a CIDFont.
+ *
+ * @return The font descriptor for this font.
+ */
+ public PDFontDescriptor getFontDescriptor()
+ {
+ if (fontDescriptor == null)
+ {
+ COSDictionary fd = (COSDictionary) dict.getDictionaryObject(COSName.FONT_DESC);
+ if (fd != null)
+ {
+ fontDescriptor = new PDFontDescriptorDictionary(fd);
+ }
+ }
+ return fontDescriptor;
+ }
+
+ /**
+ * Returns the font matrix, which represents the transformation from glyph space to text space.
+ */
+ public abstract Matrix getFontMatrix();
+
+ /**
* Returns the Type 0 font which is the parent of this font.
*
* @return parent Type 0 font
@@ -68,30 +206,23 @@ public abstract class PDCIDFont extends
}
/**
- * This will get the fonts bounding box.
- *
- * @return The fonts bounding box.
- * @throws IOException If there is an error getting the font bounding box.
+ * Returns the font's bounding box.
*/
- @Override
- public PDRectangle getFontBoundingBox() throws IOException
- {
- throw new RuntimeException("getFontBoundingBox(): Not yet implemented");
- }
+ public abstract BoundingBox getBoundingBox() throws IOException;
/**
- * This will get the default width. The default value for the default width is 1000.
+ * This will get the default width. The default value for the default width is 1000.
*
* @return The default width for the glyphs in this font.
*/
- public long getDefaultWidth()
+ private float getDefaultWidth()
{
if (defaultWidth == 0)
{
COSNumber number = (COSNumber) dict.getDictionaryObject(COSName.DW);
if (number != null)
{
- defaultWidth = number.intValue();
+ defaultWidth = number.floatValue();
}
else
{
@@ -102,121 +233,131 @@ public abstract class PDCIDFont extends
}
/**
- * This will get the font width for a character.
+ * Returns the default position vector (v).
*
- * @param c The character code to get the width for.
- * @param offset The offset into the array.
- * @param length The length of the data.
- * @return The width is in 1000 unit of text space, ie 333 or 777
- * @throws IOException If an error occurs while parsing.
+ * @param cid CID
*/
- @Override
- public float getFontWidth(byte[] c, int offset, int length) throws IOException
+ private Vector getDefaultPositionVector(int cid)
{
- float retval = getDefaultWidth();
- int code = getCodeFromArray(c, offset, length);
-
- Float widthFloat = widthCache.get(code);
- if (widthFloat != null)
+ float w0;
+ if (widths.containsKey(cid))
{
- retval = widthFloat;
+ Float w = widths.get(cid);
+ if (w != null)
+ {
+ w0 = w;
+ }
+ else
+ {
+ w0 = getDefaultWidth();
+ }
}
- return retval;
+ else
+ {
+ w0 = getDefaultWidth();
+ }
+
+ return new Vector(w0 / 2, dw2[0]);
}
- private void extractWidths()
+ /**
+ * Returns the position vector (v) in 1/1000 text space, for the given character code.
+ *
+ * @param code character code
+ * @return position vector (v)
+ */
+ public Vector getPositionVector(int code)
{
- if (widthCache == null)
+ int cid = codeToCID(code);
+ Vector v = positionVectors.get(cid);
+ if (v != null)
{
- widthCache = new HashMap<Integer, Float>();
- COSArray widths = (COSArray) dict.getDictionaryObject(COSName.W);
- if (widths != null)
- {
- int size = widths.size();
- int counter = 0;
- while (counter < size)
- {
- COSNumber firstCode = (COSNumber) widths.getObject(counter++);
- COSBase next = widths.getObject(counter++);
- if (next instanceof COSArray)
- {
- COSArray array = (COSArray) next;
- int startRange = firstCode.intValue();
- int arraySize = array.size();
- for (int i = 0; i < arraySize; i++)
- {
- COSNumber width = (COSNumber) array.get(i);
- widthCache.put(startRange + i, width.floatValue());
- }
- }
- else
- {
- COSNumber secondCode = (COSNumber) next;
- COSNumber rangeWidth = (COSNumber) widths.getObject(counter++);
- int startRange = firstCode.intValue();
- int endRange = secondCode.intValue();
- float width = rangeWidth.floatValue();
- for (int i = startRange; i <= endRange; i++)
- {
- widthCache.put(i, width);
- }
- }
- }
- }
+ return v;
+ }
+ else
+ {
+ return getDefaultPositionVector(cid);
}
}
/**
- * This will get the font height for a character.
- *
- * @param c The character code to get the height for.
- * @param offset The offset into the array.
- * @param length The length of the data.
- *
- * @return The width is in 1000 unit of text space, ie 333 or 777
+ * Returns the y-component of the vertical displacement vector (w1).
*
- * @throws IOException If an error occurs while parsing.
+ * @param code character code
+ * @return w1y
*/
- @Override
- public float getFontHeight(byte[] c, int offset, int length) throws IOException
+ public float getVerticalDisplacementVectorY(int code)
{
- float retval = 0;
- PDFontDescriptor desc = getFontDescriptor();
- float xHeight = desc.getXHeight();
- float capHeight = desc.getCapHeight();
- if (xHeight != 0f && capHeight != 0)
+ int cid = codeToCID(code);
+ Float w1y = verticalDisplacementY.get(cid);
+ if (w1y != null)
{
- // do an average of these two. Can we do better???
- retval = (xHeight + capHeight) / 2f;
+ return w1y;
}
- else if (xHeight != 0)
+ else
{
- retval = xHeight;
+ return dw2[1];
}
- else if (capHeight != 0)
+ }
+
+ /**
+ * This will get the font height for a character.
+ *
+ * @param code character code
+ * @return The height is in 1000 unit of text space, ie 333 or 777
+ */
+ public abstract float getHeight(int code) throws IOException;
+
+ /**
+ * Returns the width of the given character.
+ *
+ * @param code character code
+ */
+ public float getWidth(int code) throws IOException
+ {
+ // these widths are supposed to be consistent with the actual widths given in the CIDFont
+ // program, but PDFBOX-563 shows that when they are not, Acrobat overrides the embedded
+ // font widths with the widths given in the font dictionary
+
+ int cid = codeToCID(code);
+ if (widths.containsKey(cid))
{
- retval = capHeight;
+ Float w = widths.get(cid);
+ if (w != null)
+ {
+ return w;
+ }
+ else
+ {
+ return getDefaultWidth();
+ }
}
else
{
- retval = 0;
- }
- if (retval == 0)
- {
- retval = desc.getAscent();
+ return getWidthFromFont(code);
}
- return retval;
}
/**
+ * Returns the width of a glyph in the embedded font file.
+ *
+ * @param code character code
+ * @return width in glyph space
+ * @throws IOException if the font could not be read
+ */
+ protected abstract float getWidthFromFont(int code) throws IOException;
+
+ /**
+ * Returns true if the font file is embedded in the PDF.
+ */
+ public abstract boolean isEmbedded();
+
+ /**
* This will get the average font width for all characters.
*
* @return The width is in 1000 unit of text space, ie 333 or 777
- *
- * @throws IOException If an error occurs while parsing.
*/
- @Override
- public float getAverageFontWidth() throws IOException
+ public float getAverageFontWidth()
{
float totalWidths = 0.0f;
float characterCount = 0.0f;
@@ -258,117 +399,28 @@ public abstract class PDCIDFont extends
return average;
}
- @Override
- public float getFontWidth(int charCode)
- {
- float width = getDefaultWidth();
- if (widthCache.containsKey(charCode))
- {
- width = widthCache.get(charCode);
- }
- return width;
- }
-
/**
- * Extract the CIDSystemInfo.
- * @return the CIDSystemInfo as String
+ * Returns the CID for the given character code. If not found then CID 0 is returned.
+ *
+ * @param code character code
+ * @return CID
*/
- private String getCIDSystemInfo()
- {
- String cidSystemInfo = null;
- COSDictionary dict = (COSDictionary) this.dict.getDictionaryObject(COSName.CIDSYSTEMINFO);
- if (dict != null)
- {
- String ordering = dict.getString(COSName.ORDERING);
- String registry = dict.getString(COSName.REGISTRY);
- int supplement = dict.getInt(COSName.SUPPLEMENT);
- cidSystemInfo = registry + "-" + ordering + "-" + supplement;
- }
- return cidSystemInfo;
- }
-
- // todo: do we want to do this at all? Isn't the parent Type0 font responsible for this?
- @Override
- protected void determineEncoding()
- {
- String cidSystemInfo = getCIDSystemInfo();
- if (cidSystemInfo == null)
- {
- // todo: CIDSystemInfo is required, so this is an error (perform recovery?)
- LOG.error("Missing CIDSystemInfo in CIDFont dictionary");
- return;
- }
+ public abstract int codeToCID(int code);
- if (cidSystemInfo.contains("Identity"))
- {
- cidSystemInfo = "Identity-H";
- }
- else if (cidSystemInfo.startsWith("Adobe-UCS-"))
- {
- cidSystemInfo = "Adobe-Identity-UCS";
- }
- else
- {
- cidSystemInfo = cidSystemInfo.substring(0, cidSystemInfo.lastIndexOf('-')) + "-UCS2";
- }
-
- cmap = cmapObjects.get(cidSystemInfo);
- if (cmap == null)
- {
- InputStream cmapStream = null;
- try
- {
- // look for a predefined CMap with the given name
- cmapStream = ResourceLoader.loadResource(resourceRootCMAP + cidSystemInfo);
- if (cmapStream != null)
- {
- cmap = parseCmap(resourceRootCMAP, cmapStream);
- if (cmap == null)
- {
- LOG.error("Could not parse predefined CMAP file for '" +
- cidSystemInfo + "'");
- }
- }
- else
- {
- LOG.debug("'" + cidSystemInfo + "' isn't a predefined CMap, most " +
- "likely it's embedded in the pdf itself.");
- }
- }
- catch (IOException exception)
- {
- LOG.error("Could not find predefined CMAP file for '" + cidSystemInfo + "'");
- }
- finally
- {
- IOUtils.closeQuietly(cmapStream);
- }
- }
- }
+ /**
+ * Returns the GID for the given character code.
+ *
+ * @param code character code
+ * @return GID
+ */
+ public abstract int codeToGID(int code) throws IOException;
- @Override
- public String encode(byte[] c, int offset, int length) throws IOException
- {
- String result;
- if (cmap != null)
- {
- result = cmapEncoding(getCodeFromArray(c, offset, length), length, true, cmap);
- }
- else
- {
- result = super.encode(c, offset, length);
- }
- return result;
- }
-
- @Override
public void clear()
{
- super.clear();
- if (widthCache != null)
+ if (widths != null)
{
- widthCache.clear();
- widthCache = null;
+ widths.clear();
+ widths = null;
}
}
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java Sat Aug 30 02:26:57 2014
@@ -18,33 +18,24 @@ package org.apache.pdfbox.pdmodel.font;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fontbox.afm.FontMetric;
import org.apache.fontbox.cmap.CMap;
-import org.apache.fontbox.cmap.CMapParser;
+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.COSInteger;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.encoding.DictionaryEncoding;
-import org.apache.pdfbox.encoding.Encoding;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.common.COSArrayList;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
-import org.apache.pdfbox.pdmodel.common.PDMatrix;
-import org.apache.pdfbox.pdmodel.common.PDRectangle;
-import org.apache.pdfbox.util.ResourceLoader;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.Vector;
/**
* This is the base class for all PDF fonts.
@@ -54,334 +45,203 @@ import org.apache.pdfbox.util.ResourceLo
public abstract class PDFont implements COSObjectable
{
private static final Log LOG = LogFactory.getLog(PDFont.class);
- private static final byte[] SPACE_BYTES = { (byte) 32 }; // formerly in PDSimpleFont
+ private static final Matrix DEFAULT_FONT_MATRIX = new Matrix(0.001f, 0, 0, 0.001f, 0, 0);
- protected static final String resourceRootCMAP = "org/apache/pdfbox/resources/cmap/";
- protected static Map<String, CMap> cmapObjects =
- Collections.synchronizedMap(new HashMap<String, CMap>()); // todo: why synchronized?
+ protected final COSDictionary dict;
+ private final CMap toUnicodeCMap;
+ private PDFontDescriptor fontDescriptor;
- private static final String[] SINGLE_CHAR_STRING = new String[256];
- private static final String[][] DOUBLE_CHAR_STRING = new String[256][256];
- static
+ private List<Integer> widths;
+ private float avgFontWidth;
+ private float fontWidthOfSpace = -1f;
+ private Boolean isSymbolic;
+
+ /**
+ * Constructor for embedding.
+ */
+ protected PDFont()
{
- for (int i = 0; i < 256; i++)
- {
- try
- {
- SINGLE_CHAR_STRING[i] = new String(new byte[] { (byte) i }, "ISO-8859-1");
- }
- catch (UnsupportedEncodingException e)
- {
- // Nothing should happen here
- LOG.error(e,e);
- }
- for (int j = 0; j < 256; j++)
- {
- try
- {
- DOUBLE_CHAR_STRING[i][j] = new String(new byte[] { (byte) i, (byte) j },
- "UTF-16BE");
- }
- catch (UnsupportedEncodingException e)
- {
- // Nothing should happen here
- LOG.error(e, e);
- }
- }
- }
+ dict = new COSDictionary();
+ dict.setItem(COSName.TYPE, COSName.FONT);
+ toUnicodeCMap = null;
}
- private static String getStringFromArray(byte[] c, int offset, int length) throws IOException
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary Font dictionary.
+ */
+ protected PDFont(COSDictionary fontDictionary) throws IOException
{
- String retval;
- if (length == 1)
+ dict = fontDictionary;
+
+ // font descriptor
+ COSDictionary fd = (COSDictionary) dict.getDictionaryObject(COSName.FONT_DESC);
+ if (fd != null)
{
- retval = SINGLE_CHAR_STRING[(c[offset] + 256) % 256];
+ fontDescriptor = new PDFontDescriptorDictionary(fd);
}
- else if (length == 2)
+ else
{
- retval = DOUBLE_CHAR_STRING[(c[offset] + 256) % 256][(c[offset + 1] + 256) % 256];
+ fontDescriptor = null;
+ }
+
+ // ToUnicode CMap
+ COSBase toUnicode = dict.getDictionaryObject(COSName.TO_UNICODE);
+ if (toUnicode != null)
+ {
+ toUnicodeCMap = readCMap(toUnicode);
+ if (toUnicodeCMap != null && !toUnicodeCMap.hasUnicodeMappings())
+ {
+ LOG.warn("Invalid ToUnicode CMap in font " + getName());
+ }
}
else
{
- throw new IOException("Error:Unknown character length:" + length);
+ toUnicodeCMap = null;
}
- return retval;
}
/**
- * The Font dictionary.
+ * Returns the font descriptor, may be null.
*/
- protected COSDictionary dict;
+ public PDFontDescriptor getFontDescriptor()
+ {
+ return fontDescriptor;
+ }
/**
- * The font matrix.
+ * Sets the font descriptor.
*/
- protected PDMatrix fontMatrix = null;
-
- // CMap / Encoding
- protected CMap cmap = null; // only used when this is a Type0 font with a CMap
- protected Encoding fontEncoding = null; // only used when this font has an encoding
-
- // the CMap holding the ToUnicode mapping
- private CMap toUnicodeCmap = null;
- private boolean hasToUnicode = false;
-
- private List<Integer> widths = null;
-
- protected PDFontDescriptor fontDescriptor = null;
- private boolean widthsAreMissing = false;
-
- // formerly in PDSimpleFont
- private final HashMap<Integer, Float> fontSizes = new HashMap<Integer, Float>(128);
- private float avgFontWidth = 0.0f;
- private float avgFontHeight = 0.0f;
- private float fontWidthOfSpace = -1f;
+ void setFontDescriptor(PDFontDescriptor fontDescriptor)
+ {
+ this.fontDescriptor = fontDescriptor;
+ }
/**
- * This will clear AFM resources that are stored statically. This is usually not a problem
- * unless you want to reclaim resources for a long running process.
- *
- * SPECIAL NOTE: The font calculations are currently in COSObject, which is where they will
- * reside until PDFont is mature enough to take them over. PDFont is the appropriate place for
- * them and not in COSObject but we need font calculations for text extraction. THIS METHOD WILL
- * BE MOVED OR REMOVED TO ANOTHER LOCATION IN A FUTURE VERSION OF PDFBOX.
+ * Reads a CMap given a COS Stream or Name. May return null if a predefined CMap does not exist.
*
- * @deprecated This method will be removed in a future version of PDFBox.
+ * @param base COSName or COSStream
*/
- @Deprecated
- public static void clearResources()
+ protected final CMap readCMap(COSBase base) throws IOException
{
- cmapObjects.clear();
+ if (base instanceof COSName)
+ {
+ // predefined CMap
+ String name = ((COSName)base).getName();
+ return CMapManager.getPredefinedCMap(name);
+ }
+ else if (base instanceof COSStream)
+ {
+ // embedded CMap
+ InputStream input = null;
+ try
+ {
+ input = ((COSStream)base).getUnfilteredStream();
+ return CMapManager.parseCMap(input);
+ }
+ finally
+ {
+ IOUtils.closeQuietly(input);
+ }
+ }
+ else
+ {
+ throw new IOException("Expected Name or Stream");
+ }
}
- /**
- * Constructor.
- */
- protected PDFont()
+ @Override
+ public COSDictionary getCOSObject()
{
- dict = new COSDictionary();
- dict.setItem(COSName.TYPE, COSName.FONT);
+ return dict;
}
/**
- * Constructor.
- *
- * @param fontDictionary The font dictionary according to the PDF specification.
+ * Returns the position vector (v), in text space, for the given character.
+ * This represents the position of vertical origin relative to horizontal origin, for
+ * horizontal writing it will always be (0, 0). For vertical writing both x and y are set.
+ *
+ * @param code character code
+ * @return position vector
*/
- protected PDFont(COSDictionary fontDictionary)
+ public Vector getPositionVector(int code)
{
- dict = fontDictionary;
- determineEncoding();
+ throw new UnsupportedOperationException("Horizontal fonts have no position vector");
}
/**
- * This will get the font descriptor for this font.
- *
- * @return The font descriptor for this font.
+ * Returns the displacement vector (w0, w1) in text space, for the given character.
+ * For horizontal text only the x component is used, for vertical text only the y component.
+ *
+ * @param code character code
+ * @return displacement vector
*/
- public PDFontDescriptor getFontDescriptor()
+ public Vector getDisplacement(int code) throws IOException
{
- if (fontDescriptor == null)
- {
- COSDictionary fd = (COSDictionary) dict.getDictionaryObject(COSName.FONT_DESC);
- if (fd != null)
- {
- fontDescriptor = new PDFontDescriptorDictionary(fd);
- }
- else
- {
- FontMetric afm = getAFM();
- if (afm != null)
- {
- fontDescriptor = new PDFontDescriptorAFM(afm);
- }
- }
- }
- return fontDescriptor;
+ return new Vector(getWidth(code) / 1000, 0);
}
/**
- * Determines the encoding for the font. This method as to be overwritten, as there are
- * different possibilities to define a mapping.
+ * Returns the advance width of the given character, in glyph space.
+ *
+ * @param code character code
*/
- protected void determineEncoding()
+ public float getWidth(int code) throws IOException
{
- COSBase encoding = dict.getDictionaryObject(COSName.ENCODING);
- Encoding fontEncoding = null;
- if (encoding != null)
+ // Acrobat overrides the widths in the font program on the conforming reader's system with
+ // the widths specified in the font dictionary." (Adobe Supplement to the ISO 32000)
+ //
+ // Note: The Adobe Supplement says that the override happens "If the font program is not
+ // embedded", however PDFBOX-427 shows that it also applies to embedded fonts.
+
+ // Type1, Type1C, Type3
+ int firstChar = dict.getInt(COSName.FIRST_CHAR, -1);
+ int lastChar = dict.getInt(COSName.LAST_CHAR, -1);
+ if (getWidths().size() > 0 && code >= firstChar && code <= lastChar)
{
- if (encoding instanceof COSName)
- {
- COSName encodingName = (COSName)encoding;
- try
- {
- fontEncoding = Encoding.getInstance(encodingName);
- }
- catch (IOException exception)
- {
- LOG.debug("Debug: Could not find encoding for " + encodingName);
- }
- }
- else if (encoding instanceof COSDictionary)
- {
- try
- {
- fontEncoding = new DictionaryEncoding((COSDictionary) encoding);
- }
- catch (IOException exception)
- {
- LOG.error("Error: Could not create the DictionaryEncoding");
- }
- }
+ return getWidths().get(code - firstChar).floatValue();
}
- this.fontEncoding = fontEncoding;
- extractToUnicodeEncoding();
- }
-
- protected final void extractToUnicodeEncoding()
- {
- COSName encodingName;
- String cmapName;
- COSBase toUnicode = dict.getDictionaryObject(COSName.TO_UNICODE);
- if (toUnicode != null)
+ else
{
- hasToUnicode = true;
- if (toUnicode instanceof COSStream)
+ PDFontDescriptor fd = getFontDescriptor();
+ if (fd instanceof PDFontDescriptorDictionary &&
+ ((PDFontDescriptorDictionary) fd).hasWidths())
{
- try
- {
- InputStream is = ((COSStream) toUnicode).getUnfilteredStream();
- toUnicodeCmap = parseCmap(resourceRootCMAP, is);
- IOUtils.closeQuietly(is);
- }
- catch (IOException exception)
- {
- LOG.error("Error: Could not load embedded ToUnicode CMap");
- }
+ return fd.getMissingWidth();
}
- else if (toUnicode instanceof COSName)
+ else
{
- encodingName = (COSName) toUnicode;
- toUnicodeCmap = cmapObjects.get(encodingName.getName());
- if (toUnicodeCmap == null)
- {
- cmapName = encodingName.getName();
- String resourceName = resourceRootCMAP + cmapName;
- try
- {
- toUnicodeCmap = parseCmap(resourceRootCMAP,
- ResourceLoader.loadResource(resourceName));
- }
- catch (IOException exception)
- {
- LOG.error("Error: Could not find predefined ToUnicode CMap file for '" +
- cmapName + "'");
- }
- if (toUnicodeCmap == null)
- {
- LOG.error("Error: Could not parse predefined ToUnicode CMap file for '" +
- cmapName + "'");
- }
- }
+ // if there's nothing to override with, then obviously we fall back to the font
+ return getWidthFromFont(code);
}
}
}
- @Override
- public COSBase getCOSObject()
- {
- return dict;
- }
+ /**
+ * Returns the width of a glyph in the embedded font file.
+ *
+ * @param code character code
+ * @return width in glyph space
+ * @throws IOException if the font could not be read
+ */
+ protected abstract float getWidthFromFont(int code) throws IOException;
/**
- * This will get the font width for a character.
- *
- * @param c The character code to get the width for.
- * @param offset The offset into the array.
- * @param length The length of the data.
- * @return The width is in 1000 unit of text space, ie 333 or 777
- * @throws IOException If an error occurs while parsing.
+ * Returns true if the font file is embedded in the PDF.
*/
- public float getFontWidth(byte[] c, int offset, int length) throws IOException
- {
- int code = getCodeFromArray(c, offset, length);
- Float fontWidth = fontSizes.get(code);
- if (fontWidth == null)
- {
- fontWidth = getFontWidth(code);
- if (fontWidth <= 0)
- {
- // TODO should this be in PDType1Font??
- fontWidth = getFontWidthFromAFMFile(code);
- }
- fontSizes.put(code, fontWidth);
- }
- return fontWidth;
- }
+ public abstract boolean isEmbedded();
/**
- * This will get the font height for a character.
+ * Returns the height of the given character, in glyph space. This can be expensive to
+ * calculate. Results are only approximate.
*
- * @param c The character code to get the height for.
- * @param offset The offset into the array.
- * @param length The length of the data.
- * @return The height is in 1000 unit of text space, ie 333 or 777
- * @throws IOException If an error occurs while parsing.
- */
- public float getFontHeight(byte[] c, int offset, int length) throws IOException
- {
- // maybe there is already a precalculated value
- if (avgFontHeight > 0)
- {
- return avgFontHeight;
- }
- float retval = 0;
- FontMetric metric = getAFM();
- if (metric != null)
- {
- int code = getCodeFromArray(c, offset, length);
- Encoding encoding = getFontEncoding();
- String characterName = encoding.getName(code);
- retval = metric.getCharacterHeight(characterName);
- }
- else
- {
- PDFontDescriptor desc = getFontDescriptor();
- if (desc != null)
- {
- // the following values are all more or less accurate at least all are average
- // values. Maybe we'll find another way to get those value for every single glyph
- // in the future if needed
- PDRectangle fontBBox = desc.getFontBoundingBox();
- if (fontBBox != null)
- {
- retval = fontBBox.getHeight() / 2;
- }
- if (retval == 0)
- {
- retval = desc.getCapHeight();
- }
- if (retval == 0)
- {
- retval = desc.getAscent();
- }
- if (retval == 0)
- {
- retval = desc.getXHeight();
- if (retval > 0)
- {
- retval -= desc.getDescent();
- }
- }
- avgFontHeight = retval;
- }
- }
- return retval;
- }
+ * @param code character code
+ */
+ public abstract float getHeight(int code) throws IOException;
/**
- * This will get the width of this string for this font.
+ * Returns the width of the given Unicode string.
*
* @param string The string to get the width of.
* @return The width of the string in 1000 units of text space, ie 333 567...
@@ -389,11 +249,11 @@ public abstract class PDFont implements
*/
public float getStringWidth(String string) throws IOException
{
- byte[] data = string.getBytes("ISO-8859-1");
+ byte[] data = string.getBytes("ISO-8859-1"); // todo: *no*, these are *not* character codes
float totalWidth = 0;
for (int i = 0; i < data.length; i++)
{
- totalWidth += getFontWidth(data, i, 1);
+ totalWidth += getWidth(data[i]);
}
return totalWidth;
}
@@ -402,9 +262,9 @@ public abstract class PDFont implements
* This will get the average font width for all characters.
*
* @return The width is in 1000 unit of text space, ie 333 or 777
- * @throws IOException If an error occurs while parsing.
*/
- public float getAverageFontWidth() throws IOException
+ // todo: this method is highly suspicious, the average glyph width is not usually a good metric
+ public float getAverageFontWidth()
{
float average;
if (avgFontWidth != 0.0f)
@@ -435,7 +295,7 @@ public abstract class PDFont implements
}
else
{
- average = getAverageFontWidthFromAFMFile();
+ average = 0;
}
avgFontWidth = average;
}
@@ -443,185 +303,42 @@ public abstract class PDFont implements
}
/**
- * Used for multibyte encodings.
- *
- * @param data The array of data.
- * @param offset The offset into the array.
- * @param length The number of bytes to use.
- * @return The int value of data from the array.
- */
- public int getCodeFromArray(byte[] data, int offset, int length)
- {
- int code = 0;
- for (int i = 0; i < length; i++)
- {
- code <<= 8;
- code |= (data[offset + i] + 256) % 256;
- }
- return code;
- }
-
- /**
- * This will attempt to get the font width from an AFM file.
- *
- * @param code The character code we are trying to get.
- * @return The font width from the AFM file.
- * @throws IOException if we cannot find the width.
- */
- private float getFontWidthFromAFMFile(int code) throws IOException
- {
- float retval = 0;
- FontMetric metric = getAFM();
- if (metric != null)
- {
- String characterName = fontEncoding.getName(code);
- retval = metric.getCharacterWidth(characterName);
- }
- return retval;
- }
-
- /**
- * This will attempt to get the average font width from an AFM file.
- *
- * @return The average font width from the AFM file.
- * @throws IOException if we cannot find the width.
- */
- private float getAverageFontWidthFromAFMFile() throws IOException
- {
- float retval = 0;
- FontMetric metric = getAFM();
- if (metric != null)
- {
- retval = metric.getAverageCharacterWidth();
- }
- return retval;
- }
-
- /**
- * This will get an AFM object if one exists.
- *
- * @return The afm object from the name.
- */
- protected FontMetric getAFM()
- {
- return null;
- }
-
- /**
- * Encode the given value using the CMap of the font.
- *
- * @param code the code to encode.
- * @param length the byte length of the given code.
- * @param isCIDFont indicates that the used font is a CID font.
- *
- * @return The value of the encoded character.
- * @throws IOException if something went wrong
- */
- protected final String cmapEncoding(int code, int length, boolean isCIDFont, CMap sourceCmap)
- throws IOException
- {
- String retval = null;
- // there is not sourceCmap if this is a descendant font
- if (sourceCmap == null)
- {
- sourceCmap = cmap;
- }
- if (sourceCmap != null)
- {
- retval = sourceCmap.lookup(code, length);
- if (retval == null && isCIDFont)
- {
- retval = sourceCmap.lookupCID(code);
- }
- }
- return retval;
- }
-
- /**
- * This will perform the encoding of a character if needed.
- *
- * @param c The character to encode.
- * @param offset The offset into the array to get the data
- * @param length The number of bytes to read.
- * @return The value of the encoded character.
- * @throws IOException If there is an error during the encoding.
+ * Reads a character code from a content stream string. Codes may be up to 4 bytes long.
+ *
+ * @param in string stream
+ * @return character code
+ * @throws IOException if the CMap or stream cannot be read
*/
- public String encode(byte[] c, int offset, int length) throws IOException
- {
- String retval = null;
- int code = getCodeFromArray(c, offset, length);
- if (toUnicodeCmap != null)
- {
- retval = cmapEncoding(code, length, false, toUnicodeCmap);
- }
- if (retval == null && cmap != null)
- {
- retval = cmapEncoding(code, length, false, cmap);
- }
-
- // there is no cmap but probably an encoding with a suitable mapping
- if (retval == null)
- {
- if (fontEncoding != null)
- {
- retval = fontEncoding.getCharacter(code);
- }
- if (retval == null && (cmap == null || length == 2))
- {
- retval = getStringFromArray(c, offset, length);
- }
- }
- return retval;
- }
-
- public int encodeToCID(byte[] c, int offset, int length) throws IOException
- {
- int code = -1;
- if (encode(c, offset, length) != null)
- {
- code = getCodeFromArray(c, offset, length);
- }
- return code;
- }
+ public abstract int readCode(InputStream in) throws IOException;
/**
- * Parse the given CMap.
- *
- * @param cmapRoot the root path pointing to the provided CMaps
- * @param cmapStream the CMap to be read
- * @return the parsed CMap
+ * Returns the Unicode character sequence which corresponds to the given character code.
+ *
+ * @param code character code
+ * @return Unicode character(s)
*/
- protected final CMap parseCmap(String cmapRoot, InputStream cmapStream)
+ public String toUnicode(int code)
{
- CMap targetCmap = null;
- if (cmapStream != null)
+ // if the font dictionary contains a ToUnicode CMap, use that CMap
+ if (toUnicodeCMap != null)
{
- CMapParser parser = new CMapParser();
- try
+ if (toUnicodeCMap.getName() != null && toUnicodeCMap.getName().startsWith("Identity-"))
{
- targetCmap = parser.parse(cmapRoot, cmapStream);
- // limit the cache to external CMaps
- if (cmapRoot != null)
- {
- cmapObjects.put(targetCmap.getName(), targetCmap);
- }
+ // handle the undocumented case of using Identity-H/V as a ToUnicode CMap, this
+ // isn't actually valid as the Identity-x CMaps are code->CID maps, not
+ // code->Unicode maps. See sample_fonts_solidconvertor.pdf for an example.
+ return new String(new char[] { (char) code });
}
- catch (IOException exception)
+ else
{
- LOG.error("An error occurs while reading a CMap", exception);
+ // proceed as normal
+ return toUnicodeCMap.toUnicode(code);
}
}
- return targetCmap;
- }
- /**
- * This will get or create the encoder.
- *
- * @return The encoding to use.
- */
- public Encoding getFontEncoding()
- {
- return fontEncoding;
+ // if no value has been produced, there is no way to obtain Unicode for the character.
+ // this behaviour can be overridden is subclasses, but this method *must* return null here
+ return null;
}
/**
@@ -636,8 +353,6 @@ public abstract class PDFont implements
/**
* This will get the subtype of font.
- *
- * @return The type of font that this is.
*/
public String getSubType()
{
@@ -645,59 +360,52 @@ public abstract class PDFont implements
}
/**
- * Determines if the font is a type 1 font.
- *
- * @return returns true if the font is a type 1 font
- */
- public boolean isType1Font()
- {
- return "Type1".equals(getSubType());
- }
-
- /**
- * Determines if the font is a type 3 font.
- *
- * @return returns true if the font is a type 3 font
- */
- public boolean isType3Font()
- {
- return "Type3".equals(getSubType());
- }
-
- /**
- * Determines if the font is a type 0 font.
- *
- * @return returns true if the font is a type 0 font
+ * Returns true the font is a symbolic (that is, it does not use the Adobe Standard Roman
+ * character set).
*/
- public boolean isType0Font()
+ public final boolean isSymbolic()
{
- return "Type0".equals(getSubType());
+ if (isSymbolic == null)
+ {
+ Boolean result = isFontSymbolic();
+ if (result != null)
+ {
+ isSymbolic = result;
+ }
+ else
+ {
+ // unless we can prove that the font is symbolic, we assume that it is not
+ isSymbolic = true;
+ }
+ }
+ return isSymbolic;
}
/**
- * Determines if the font is a true type font.
- *
- * @return returns true if the font is a true type font
+ * Internal implementation of isSymbolic, allowing for the fact that the result may be
+ * indeterminate.
*/
- public boolean isTrueTypeFont()
+ protected Boolean isFontSymbolic()
{
- return "TrueType".equals(getSubType());
+ return getSymbolicFlag();
}
/**
- * Determines if the font is a symbolic font.
- *
- * @return returns true if the font is a symbolic font
+ * Returns the value of the symbolic flag, allowing for the fact that the result may be
+ * indeterminate.
*/
- public boolean isSymbolicFont()
+ protected Boolean getSymbolicFlag()
{
- return getFontDescriptor().isSymbolic();
+ if (getFontDescriptor() != null)
+ {
+ // fixme: isSymbolic() defaults to false if the flag is missing so we can't trust this
+ return getFontDescriptor().isSymbolic();
+ }
+ return null;
}
/**
- * The PostScript name of the font.
- *
- * @return The postscript name of the font.
+ * Returns the PostScript name of the font.
*/
public String getBaseFont()
{
@@ -705,33 +413,26 @@ public abstract class PDFont implements
}
/**
- * The code for the first char or -1 if there is none.
- *
- * @return The code for the first character.
+ * Returns the name of this font, either the PostScript "BaseName" or the Type 3 "Name".
*/
- public int getFirstChar()
+ public String getName()
{
- return dict.getInt(COSName.FIRST_CHAR, -1);
+ return getBaseFont();
}
/**
- * The code for the last char or -1 if there is none.
- *
- * @return The code for the last character.
+ * Returns the font's bounding box.
*/
- public int getLastChar()
- {
- return dict.getInt(COSName.LAST_CHAR, -1);
- }
+ public abstract BoundingBox getBoundingBox() throws IOException;
/**
* The widths of the characters. This will be null for the standard 14 fonts.
- *
+ *
* @return The widths of the characters.
*/
- public List<Integer> getWidths()
+ protected final List<Integer> getWidths()
{
- if (widths == null && !widthsAreMissing)
+ if (widths == null)
{
COSArray array = (COSArray) dict.getDictionaryObject(COSName.WIDTHS);
if (array != null)
@@ -740,94 +441,18 @@ public abstract class PDFont implements
}
else
{
- widthsAreMissing = true;
+ widths = Collections.emptyList();
}
}
return widths;
}
/**
- * This will get the matrix that is used to transform glyph space to text space. By default
- * there are 1000 glyph units to 1 text space unit, but type3 fonts can use any value.
- *
- * Note: If this is a type3 font then it can be modified via the PDType3Font.setFontMatrix,
- * otherwise this is a read-only property.
- *
- * @return The matrix to transform from glyph space to text space.
+ * Returns the font matrix, which represents the transformation from glyph space to text space.
*/
- public PDMatrix getFontMatrix()
+ public Matrix getFontMatrix()
{
- if (fontMatrix == null)
- {
- COSArray array = (COSArray) dict.getDictionaryObject(COSName.FONT_MATRIX);
- if (array == null)
- {
- array = new COSArray();
- array.add(new COSFloat(0.001f));
- array.add(COSInteger.ZERO);
- array.add(COSInteger.ZERO);
- array.add(new COSFloat(0.001f));
- array.add(COSInteger.ZERO);
- array.add(COSInteger.ZERO);
- }
- fontMatrix = new PDMatrix(array);
- }
- return fontMatrix;
- }
-
- /**
- * This will get the fonts bounding box.
- *
- * @return The fonts bounding box.
- * @throws IOException If there is an error getting the bounding box.
- */
- public PDRectangle getFontBoundingBox() throws IOException
- {
- return getFontDescriptor().getFontBoundingBox();
- }
-
- /**
- * Determines the width of the given character.
- *
- * @param charCode the code of the given character
- * @return the width of the character
- */
- public float getFontWidth(int charCode)
- {
- float width = -1;
- int firstChar = getFirstChar();
- int lastChar = getLastChar();
- if (charCode >= firstChar && charCode <= lastChar)
- {
- // maybe the font doesn't provide any widths
- if (!widthsAreMissing)
- {
- getWidths();
- if (widths != null)
- {
- width = widths.get(charCode - firstChar).floatValue();
- }
- }
- }
- else
- {
- PDFontDescriptor fd = getFontDescriptor();
- if (fd instanceof PDFontDescriptorDictionary)
- {
- width = fd.getMissingWidth();
- }
- }
- return width;
- }
-
- /**
- * Determines if a font as a ToUnicode entry.
- *
- * @return true if the font has a ToUnicode entry
- */
- public boolean hasToUnicode()
- {
- return hasToUnicode;
+ return DEFAULT_FONT_MATRIX;
}
/**
@@ -844,15 +469,15 @@ public abstract class PDFont implements
{
if (toUnicode != null)
{
- int spaceMapping = toUnicodeCmap.getSpaceMapping();
+ int spaceMapping = toUnicodeCMap.getSpaceMapping();
if (spaceMapping > -1)
{
- fontWidthOfSpace = getFontWidth(spaceMapping);
+ fontWidthOfSpace = getWidth(spaceMapping);
}
}
else
{
- fontWidthOfSpace = getFontWidth(SPACE_BYTES, 0, 1);
+ fontWidthOfSpace = getWidth(32);
}
// use the average font width as fall back
if (fontWidthOfSpace <= 0)
@@ -870,24 +495,9 @@ public abstract class PDFont implements
}
/**
- * Returns the toUnicode mapping if present.
- *
- * @return the CMap representing the toUnicode mapping
+ * Returns true if the font uses vertical writing mode.
*/
- public CMap getToUnicodeCMap()
- {
- return toUnicodeCmap;
- }
-
- /**
- * Returns the CMap if present.
- *
- * @return the CMap representing the character encoding
- */
- public CMap getCMap()
- {
- return cmap;
- }
+ public abstract boolean isVertical();
/**
* Calling this will release all cached information.
@@ -907,4 +517,10 @@ public abstract class PDFont implements
{
return this.getCOSObject().hashCode();
}
+
+ @Override
+ public String toString()
+ {
+ return getClass().getSimpleName() + " " + getName();
+ }
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java Sat Aug 30 02:26:57 2014
@@ -17,30 +17,26 @@
package org.apache.pdfbox.pdmodel.font;
import java.io.IOException;
-
-import org.apache.fontbox.afm.FontMetric;
-
+import org.apache.fontbox.afm.FontMetrics;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
-
import org.apache.fontbox.util.BoundingBox;
/**
* This class represents the font descriptor when the font information
* is coming from an AFM file.
*
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.3 $
+ * @author Ben Litchfield
*/
public class PDFontDescriptorAFM extends PDFontDescriptor
{
- private FontMetric afm;
+ private FontMetrics afm;
/**
* Constructor.
*
* @param afmFile The AFM file.
*/
- public PDFontDescriptorAFM( FontMetric afmFile )
+ public PDFontDescriptorAFM( FontMetrics afmFile )
{
afm = afmFile;
}
@@ -158,6 +154,12 @@ public class PDFontDescriptorAFM extends
throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
}
+ @Override
+ public boolean isSymbolic()
+ {
+ return afm.getEncodingScheme().equals("FontSpecific");
+ }
+
/**
* This will get the fonts bouding box.
*
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java Sat Aug 30 02:26:57 2014
@@ -42,16 +42,16 @@ public class PDFontDescriptorDictionary
private int flags = -1;
/**
- * Constructor.
+ * Package-private constructor, for internal PDFBox use only.
*/
- public PDFontDescriptorDictionary()
+ PDFontDescriptorDictionary()
{
dic = new COSDictionary();
dic.setItem( COSName.TYPE, COSName.FONT_DESC );
}
/**
- * Constructor.
+ * Creates a PDFontDescriptor from a COS dictionary.
*
* @param desc The wrapped COS Dictionary.
*/
@@ -475,6 +475,14 @@ public class PDFontDescriptorDictionary
}
/**
+ * Returns true if widths are present in the font descriptor.
+ */
+ public boolean hasWidths()
+ {
+ return dic.containsKey(COSName.WIDTHS) || dic.containsKey(COSName.MISSING_WIDTH);
+ }
+
+ /**
* This will get the missing width for the font.
*
* @return The missing width value.
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java Sat Aug 30 02:26:57 2014
@@ -18,6 +18,7 @@ package org.apache.pdfbox.pdmodel.font;
import java.io.IOException;
+import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.commons.logging.Log;
@@ -53,6 +54,14 @@ public class PDFontFactory
COSName subType = dictionary.getCOSName(COSName.SUBTYPE);
if (COSName.TYPE1.equals(subType))
{
+ COSBase fd = dictionary.getDictionaryObject(COSName.FONT_DESC);
+ if (fd != null && fd instanceof COSDictionary)
+ {
+ if (((COSDictionary)fd).containsKey(COSName.FONT_FILE3))
+ {
+ return new PDType1CFont(dictionary);
+ }
+ }
return new PDType1Font(dictionary);
}
else if (COSName.MM_TYPE1.equals(subType))
@@ -101,17 +110,17 @@ public class PDFontFactory
COSName type = dictionary.getCOSName(COSName.TYPE, COSName.FONT);
if (!COSName.FONT.equals(type))
{
- throw new IOException("Expected 'Font' dictionary but found '" + type.getName() + "'");
+ throw new IllegalArgumentException("Expected 'Font' dictionary but found '" + type.getName() + "'");
}
COSName subType = dictionary.getCOSName(COSName.SUBTYPE);
if (COSName.CID_FONT_TYPE0.equals(subType))
{
- return new PDCIDFontType0Font(dictionary, parent);
+ return new PDCIDFontType0(dictionary, parent);
}
else if (COSName.CID_FONT_TYPE2.equals(subType))
{
- return new PDCIDFontType2Font(dictionary, parent);
+ return new PDCIDFontType2(dictionary, parent);
}
else
{
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java Sat Aug 30 02:26:57 2014
@@ -17,7 +17,8 @@
package org.apache.pdfbox.pdmodel.font;
import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSName;
+
+import java.io.IOException;
/**
* Type 1 Multiple Master Font.
@@ -27,19 +28,11 @@ import org.apache.pdfbox.cos.COSName;
public class PDMMType1Font extends PDType1Font
{
/**
- * Constructor.
- */
- public PDMMType1Font()
- {
- dict.setItem(COSName.SUBTYPE, COSName.MM_TYPE1);
- }
-
- /**
- * Constructor.
+ * Creates an MMType1Font from a Font dictionary in a PDF.
*
- * @param fontDictionary The font dictionary according to the PDF specification.
+ * @param fontDictionary font dictionary
*/
- public PDMMType1Font(COSDictionary fontDictionary)
+ public PDMMType1Font(COSDictionary fontDictionary) throws IOException
{
super(fontDictionary);
}