Author: jahewson Date: Wed Aug 10 16:06:07 2016 New Revision: 1755774 URL: http://svn.apache.org/viewvc?rev=1755774&view=rev Log: PDFBOX-3459: Move Glyph2D functionality into PDFont subclasses
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java (with props) Removed: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/CIDType0Glyph2D.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/Glyph2D.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/TTFGlyph2D.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/Type1Glyph2D.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java Wed Aug 10 16:06:07 2016 @@ -57,10 +57,9 @@ public class PDCIDFontType0 extends PDCI private final Map<Integer, Float> glyphHeights = new HashMap<Integer, Float>(); private final boolean isEmbedded; private final boolean isDamaged; - + private final AffineTransform fontMatrixTransform; private Float avgWidth = null; private Matrix fontMatrix; - private final AffineTransform fontMatrixTransform; private BoundingBox fontBBox; /** @@ -190,16 +189,6 @@ public class PDCIDFontType0 extends PDCI return fontMatrix; } - private class ByteSource implements CFFParser.ByteSource - { - @Override - public byte[] getBytes() throws IOException - { - PDStream ff3Stream = getFontDescriptor().getFontFile3(); - return IOUtils.toByteArray(ff3Stream.createInputStream()); - } - } - @Override public BoundingBox getBoundingBox() { @@ -328,6 +317,12 @@ public class PDCIDFontType0 extends PDCI } @Override + public GeneralPath getNormalizedPath(int code) throws IOException + { + return getPath(code); + } + + @Override public boolean hasGlyph(int code) throws IOException { int cid = codeToCID(code); @@ -448,4 +443,14 @@ public class PDCIDFontType0 extends PDCI // todo: not implemented, highly suspect return 500; } + + private class ByteSource implements CFFParser.ByteSource + { + @Override + public byte[] getBytes() throws IOException + { + PDStream ff3Stream = getFontDescriptor().getFontFile3(); + return IOUtils.toByteArray(ff3Stream.createInputStream()); + } + } } Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Wed Aug 10 16:06:07 2016 @@ -16,6 +16,7 @@ */ package org.apache.pdfbox.pdmodel.font; +import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.io.IOException; import java.io.InputStream; @@ -447,6 +448,36 @@ public class PDCIDFontType2 extends PDCI } } + @Override + public GeneralPath getNormalizedPath(int code) throws IOException + { + boolean hasScaling = ttf.getUnitsPerEm() != 1000; + float scale = 1000f / ttf.getUnitsPerEm(); + int gid = codeToGID(code); + + GeneralPath path = getPath(code); + + // Acrobat only draws GID 0 for embedded CIDFonts, see PDFBOX-2372 + if (gid == 0 && !isEmbedded()) + { + path = null; + } + + if (path == null) + { + // empty glyph (e.g. space, newline) + return new GeneralPath(); + } + else + { + if (hasScaling) + { + path.transform(AffineTransform.getScaleInstance(scale, scale)); + } + return path; + } + } + @Override public boolean hasGlyph(int code) throws IOException { Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Wed Aug 10 16:06:07 2016 @@ -16,6 +16,7 @@ */ package org.apache.pdfbox.pdmodel.font; +import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.io.File; import java.io.FileInputStream; @@ -75,6 +76,86 @@ public class PDTrueTypeFont extends PDSi } } + private final TrueTypeFont ttf; + private final boolean isEmbedded; + private final boolean isDamaged; + private CmapSubtable cmapWinUnicode = null; + private CmapSubtable cmapWinSymbol = null; + private CmapSubtable cmapMacRoman = null; + private boolean cmapInitialized = false; + private Map<Integer, Integer> gidToCode; // for embedding + private BoundingBox fontBBox; + + /** + * Creates a new TrueType font from a Font dictionary. + * + * @param fontDictionary The font dictionary according to the PDF specification. + */ + public PDTrueTypeFont(COSDictionary fontDictionary) throws IOException + { + super(fontDictionary); + + TrueTypeFont ttfFont = null; + boolean fontIsDamaged = false; + if (getFontDescriptor() != null) + { + PDFontDescriptor fd = super.getFontDescriptor(); + PDStream ff2Stream = fd.getFontFile2(); + if (ff2Stream != null) + { + try + { + // embedded + TTFParser ttfParser = new TTFParser(true); + ttfFont = ttfParser.parse(ff2Stream.createInputStream()); + } + catch (NullPointerException e) // TTF parser is buggy + { + LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e); + fontIsDamaged = true; + } + catch (IOException e) + { + LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e); + fontIsDamaged = true; + } + } + } + isEmbedded = ttfFont != null; + isDamaged = fontIsDamaged; + + // substitute + if (ttfFont == null) + { + FontMapping<TrueTypeFont> mapping = FontMappers.instance() + .getTrueTypeFont(getBaseFont(), + getFontDescriptor()); + ttfFont = mapping.getFont(); + + if (mapping.isFallback()) + { + LOG.warn("Using fallback font '" + ttfFont + "' for '" + getBaseFont() + "'"); + } + } + ttf = ttfFont; + readEncoding(); + } + /** + * Creates a new TrueType font for embedding. + */ + private PDTrueTypeFont(PDDocument document, InputStream ttfStream, Encoding encoding) + throws IOException + { + PDTrueTypeFontEmbedder embedder = new PDTrueTypeFontEmbedder(document, dict, ttfStream, + encoding); + this.encoding = encoding; + ttf = embedder.getTrueTypeFont(); + setFontDescriptor(embedder.getFontDescriptor()); + isEmbedded = true; + isDamaged = false; + glyphList = GlyphList.getAdobeGlyphList(); + } + /** * Loads a TTF to be embedded into a document as a simple font. * @@ -110,7 +191,7 @@ public class PDTrueTypeFont extends PDSi { return new PDTrueTypeFont(doc, input, encoding); } - + /** * Loads a TTF to be embedded into a document as a simple font. Only supports WinAnsiEncoding. * @@ -143,72 +224,6 @@ public class PDTrueTypeFont extends PDSi return new PDTrueTypeFont(doc, input, WinAnsiEncoding.INSTANCE); } - private CmapSubtable cmapWinUnicode = null; - private CmapSubtable cmapWinSymbol = null; - private CmapSubtable cmapMacRoman = null; - private boolean cmapInitialized = false; - private Map<Integer, Integer> gidToCode; // for embedding - - private final TrueTypeFont ttf; - private final boolean isEmbedded; - private final boolean isDamaged; - private BoundingBox fontBBox; - - /** - * Creates a new TrueType font from a Font dictionary. - * - * @param fontDictionary The font dictionary according to the PDF specification. - */ - public PDTrueTypeFont(COSDictionary fontDictionary) throws IOException - { - super(fontDictionary); - - TrueTypeFont ttfFont = null; - boolean fontIsDamaged = false; - if (getFontDescriptor() != null) - { - PDFontDescriptor fd = super.getFontDescriptor(); - PDStream ff2Stream = fd.getFontFile2(); - if (ff2Stream != null) - { - try - { - // embedded - TTFParser ttfParser = new TTFParser(true); - ttfFont = ttfParser.parse(ff2Stream.createInputStream()); - } - catch (NullPointerException e) // TTF parser is buggy - { - LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e); - fontIsDamaged = true; - } - catch (IOException e) - { - LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e); - fontIsDamaged = true; - } - } - } - isEmbedded = ttfFont != null; - isDamaged = fontIsDamaged; - - // substitute - if (ttfFont == null) - { - FontMapping<TrueTypeFont> mapping = FontMappers.instance() - .getTrueTypeFont(getBaseFont(), - getFontDescriptor()); - ttfFont = mapping.getFont(); - - if (mapping.isFallback()) - { - LOG.warn("Using fallback font '" + ttfFont + "' for '" + getBaseFont() + "'"); - } - } - ttf = ttfFont; - readEncoding(); - } - /** * Returns the PostScript name of the font. */ @@ -271,22 +286,6 @@ public class PDTrueTypeFont extends PDSi } } - /** - * Creates a new TrueType font for embedding. - */ - private PDTrueTypeFont(PDDocument document, InputStream ttfStream, Encoding encoding) - throws IOException - { - PDTrueTypeFontEmbedder embedder = new PDTrueTypeFontEmbedder(document, dict, ttfStream, - encoding); - this.encoding = encoding; - ttf = embedder.getTrueTypeFont(); - setFontDescriptor(embedder.getFontDescriptor()); - isEmbedded = true; - isDamaged = false; - glyphList = GlyphList.getAdobeGlyphList(); - } - @Override public int readCode(InputStream in) throws IOException { @@ -494,10 +493,40 @@ public class PDTrueTypeFont extends PDSi } @Override + public GeneralPath getNormalizedPath(int code) throws IOException + { + boolean hasScaling = ttf.getUnitsPerEm() != 1000; + float scale = 1000f / ttf.getUnitsPerEm(); + int gid = codeToGID(code); + + GeneralPath path = getPath(code); + + // Acrobat only draws GID 0 for embedded or "Standard 14" fonts, see PDFBOX-2372 + if (gid == 0 && !isEmbedded() && !isStandard14()) + { + path = null; + } + + if (path == null) + { + // empty glyph (e.g. space, newline) + return new GeneralPath(); + } + else + { + if (hasScaling) + { + path.transform(AffineTransform.getScaleInstance(scale, scale)); + } + return path; + } + } + + @Override public boolean hasGlyph(String name) throws IOException { int gid = ttf.nameToGID(name); - return gid != 0; + return !(gid == 0 || gid >= ttf.getMaximumProfile().getNumGlyphs()); } @Override Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java Wed Aug 10 16:06:07 2016 @@ -46,13 +46,47 @@ public class PDType0Font extends PDFont private static final Log LOG = LogFactory.getLog(PDType0Font.class); private final PDCIDFont descendantFont; + private final Set<Integer> noUnicode = new HashSet<Integer>(); private CMap cMap, cMapUCS2; private boolean isCMapPredefined; private boolean isDescendantCJK; private PDCIDFontType2Embedder embedder; - private final Set<Integer> noUnicode = new HashSet<Integer>(); /** + * Constructor for reading a Type0 font from a PDF file. + * + * @param fontDictionary The font dictionary according to the PDF specification. + * @throws IOException if the descendant font is missing. + */ + public PDType0Font(COSDictionary fontDictionary) throws IOException + { + super(fontDictionary); + COSArray descendantFonts = (COSArray)dict.getDictionaryObject(COSName.DESCENDANT_FONTS); + COSDictionary descendantFontDictionary = (COSDictionary) descendantFonts.getObject(0); + + if (descendantFontDictionary == null) + { + throw new IOException("Missing descendant font dictionary"); + } + + descendantFont = PDFontFactory.createDescendantFont(descendantFontDictionary, this); + readEncoding(); + fetchCMapUCS2(); + } + + /** + * Private. Creates a new TrueType font for embedding. + */ + private PDType0Font(PDDocument document, TrueTypeFont ttf, boolean embedSubset) + throws IOException + { + embedder = new PDCIDFontType2Embedder(document, dict, ttf, embedSubset, this); + descendantFont = embedder.getCIDFont(); + readEncoding(); + fetchCMapUCS2(); + } + + /** * Loads a TTF to be embedded into a document as a Type 0 font. * * @param doc The PDF document that will hold the embedded font. @@ -108,40 +142,6 @@ public class PDType0Font extends PDFont return new PDType0Font(doc, ttf, embedSubset); } - /** - * Constructor for reading a Type0 font from a PDF file. - * - * @param fontDictionary The font dictionary according to the PDF specification. - * @throws IOException if the descendant font is missing. - */ - public PDType0Font(COSDictionary fontDictionary) throws IOException - { - super(fontDictionary); - COSArray descendantFonts = (COSArray)dict.getDictionaryObject(COSName.DESCENDANT_FONTS); - COSDictionary descendantFontDictionary = (COSDictionary) descendantFonts.getObject(0); - - if (descendantFontDictionary == null) - { - throw new IOException("Missing descendant font dictionary"); - } - - descendantFont = PDFontFactory.createDescendantFont(descendantFontDictionary, this); - readEncoding(); - fetchCMapUCS2(); - } - - /** - * Private. Creates a new TrueType font for embedding. - */ - private PDType0Font(PDDocument document, TrueTypeFont ttf, boolean embedSubset) - throws IOException - { - embedder = new PDCIDFontType2Embedder(document, dict, ttf, embedSubset, this); - descendantFont = embedder.getCIDFont(); - readEncoding(); - fetchCMapUCS2(); - } - @Override public void addToSubset(int codePoint) { @@ -506,6 +506,13 @@ public class PDType0Font extends PDFont return descendantFont.getPath(code); } + + @Override + public GeneralPath getNormalizedPath(int code) throws IOException + { + return descendantFont.getNormalizedPath(code); + } + @Override public boolean hasGlyph(int code) throws IOException { Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java Wed Aug 10 16:06:07 2016 @@ -51,19 +51,18 @@ import static org.apache.pdfbox.pdmodel. * @author Villu Ruusmann * @author John Hewson */ -public class PDType1CFont extends PDSimpleFont +public class PDType1CFont extends PDSimpleFont implements PDVectorFont { private static final Log LOG = LogFactory.getLog(PDType1CFont.class); private final Map<String, Float> glyphHeights = new HashMap<String, Float>(); - private Float avgWidth = null; - private Matrix fontMatrix; private final AffineTransform fontMatrixTransform; - private final CFFType1Font cffFont; // embedded font private final FontBoxFont genericFont; // embedded or system font for rendering private final boolean isEmbedded; private final boolean isDamaged; + private Float avgWidth = null; + private Matrix fontMatrix; private BoundingBox fontBBox; /** @@ -133,16 +132,6 @@ public class PDType1CFont extends PDSimp fontMatrixTransform.scale(1000, 1000); } - private class ByteSource implements CFFParser.ByteSource - { - @Override - public byte[] getBytes() throws IOException - { - PDStream ff3Stream = getFontDescriptor().getFontFile3(); - return IOUtils.toByteArray(ff3Stream.createInputStream()); - } - } - @Override public FontBoxFont getFontBoxFont() { @@ -172,6 +161,32 @@ public class PDType1CFont extends PDSimp } @Override + public boolean hasGlyph(int code) throws IOException + { + String name = getEncoding().getName(code); + return hasGlyph(name); + } + + @Override + public GeneralPath getPath(int code) throws IOException + { + String name = getEncoding().getName(code); + return getPath(name); + } + + @Override + public GeneralPath getNormalizedPath(int code) throws IOException + { + String name = getEncoding().getName(code); + GeneralPath path = getPath(name); + if (path == null) + { + return getPath(".notdef"); + } + return path; + } + + @Override public boolean hasGlyph(String name) throws IOException { return genericFont.hasGlyph(name); @@ -211,7 +226,7 @@ public class PDType1CFont extends PDSimp { return getEncoding().getName(code); } - + @Override protected Encoding readEncodingFromFont() throws IOException { @@ -234,7 +249,7 @@ public class PDType1CFont extends PDSimp } } } - + @Override public int readCode(InputStream in) throws IOException { @@ -331,7 +346,7 @@ public class PDType1CFont extends PDSimp int code = inverted.get(name); return new byte[] { (byte)code }; } - + @Override public float getStringWidth(String string) throws IOException { @@ -344,7 +359,7 @@ public class PDType1CFont extends PDSimp } return width; } - + @Override public float getAverageFontWidth() { @@ -371,7 +386,7 @@ public class PDType1CFont extends PDSimp // todo: not implemented, highly suspect return 500; } - + /** * Maps a PostScript glyph name to the name in the underlying font, for example when * using a TTF font we might map "W" to "uni0057". @@ -397,4 +412,14 @@ public class PDType1CFont extends PDSimp } return ".notdef"; } + + private class ByteSource implements CFFParser.ByteSource + { + @Override + public byte[] getBytes() throws IOException + { + PDStream ff3Stream = getFontDescriptor().getFontFile3(); + return IOUtils.toByteArray(ff3Stream.createInputStream()); + } + } } Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java Wed Aug 10 16:06:07 2016 @@ -42,38 +42,20 @@ import org.apache.pdfbox.pdmodel.common. import org.apache.pdfbox.pdmodel.font.encoding.Encoding; import org.apache.pdfbox.pdmodel.font.encoding.StandardEncoding; import org.apache.pdfbox.pdmodel.font.encoding.Type1Encoding; +import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; +import org.apache.pdfbox.pdmodel.font.encoding.ZapfDingbatsEncoding; import org.apache.pdfbox.util.Matrix; import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; -import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; -import org.apache.pdfbox.pdmodel.font.encoding.ZapfDingbatsEncoding; /** * A PostScript Type 1 Font. * * @author Ben Litchfield */ -public class PDType1Font extends PDSimpleFont +public class PDType1Font extends PDSimpleFont implements PDVectorFont { - private static final Log LOG = LogFactory.getLog(PDType1Font.class); - - // alternative names for glyphs which are commonly encountered - private static final Map<String, String> ALT_NAMES = new HashMap<String, String>(); - static - { - ALT_NAMES.put("ff", "f_f"); - ALT_NAMES.put("ffi", "f_f_i"); - ALT_NAMES.put("ffl", "f_f_l"); - ALT_NAMES.put("fi", "f_i"); - ALT_NAMES.put("fl", "f_l"); - ALT_NAMES.put("st", "s_t"); - ALT_NAMES.put("IJ", "I_J"); - ALT_NAMES.put("ij", "i_j"); - ALT_NAMES.put("ellipsis", "elipsis"); // misspelled in ArialMT - } - private static final int PFB_START_MARKER = 0x80; - // todo: replace with enum? or getters? public static final PDType1Font TIMES_ROMAN = new PDType1Font("Times-Roman"); public static final PDType1Font TIMES_BOLD = new PDType1Font("Times-Bold"); @@ -89,6 +71,23 @@ public class PDType1Font extends PDSimpl public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font("Courier-BoldOblique"); public static final PDType1Font SYMBOL = new PDType1Font("Symbol"); public static final PDType1Font ZAPF_DINGBATS = new PDType1Font("ZapfDingbats"); + private static final Log LOG = LogFactory.getLog(PDType1Font.class); + // alternative names for glyphs which are commonly encountered + private static final Map<String, String> ALT_NAMES = new HashMap<String, String>(); + private static final int PFB_START_MARKER = 0x80; + + static + { + ALT_NAMES.put("ff", "f_f"); + ALT_NAMES.put("ffi", "f_f_i"); + ALT_NAMES.put("ffl", "f_f_l"); + ALT_NAMES.put("fi", "f_i"); + ALT_NAMES.put("fl", "f_l"); + ALT_NAMES.put("st", "s_t"); + ALT_NAMES.put("IJ", "I_J"); + ALT_NAMES.put("ij", "i_j"); + ALT_NAMES.put("ellipsis", "elipsis"); // misspelled in ArialMT + } /** * embedded font. @@ -102,14 +101,13 @@ public class PDType1Font extends PDSimpl private final boolean isEmbedded; private final boolean isDamaged; - private Matrix fontMatrix; private final AffineTransform fontMatrixTransform; - private BoundingBox fontBBox; - /** * to improve encoding speed. */ private final Map <Integer,byte[]> codeToBytesMap; + private Matrix fontMatrix; + private BoundingBox fontBBox; /** * Creates a Type 1 standard 14 font for embedding. @@ -562,12 +560,37 @@ public class PDType1Font extends PDSimpl } @Override + public GeneralPath getPath(int code) throws IOException + { + String name = getEncoding().getName(code); + return getPath(name); + } + + @Override + public GeneralPath getNormalizedPath(int code) throws IOException + { + String name = getEncoding().getName(code); + GeneralPath path = getPath(name); + if (path == null) + { + return getPath(".notdef"); + } + return path; + } + + @Override public boolean hasGlyph(String name) throws IOException { return genericFont.hasGlyph(getNameInFont(name)); } @Override + public boolean hasGlyph(int code) throws IOException + { + return !getEncoding().getName(code).equals(".notdef"); + } + + @Override public final Matrix getFontMatrix() { if (fontMatrix == null) Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java Wed Aug 10 16:06:07 2016 @@ -34,6 +34,16 @@ public interface PDVectorFont * @throws java.io.IOException if the font could not be read */ GeneralPath getPath(int code) throws IOException; + + /** + * Returns the normalized glyph path for the given character code. The resulting path is + * normalized to the PostScript 1000 unit square, and fallback glyphs are returned + * where appropriate, e.g. for missing glyphs. + * + * @param code character code + * @throws java.io.IOException if the font could not be read + */ + GeneralPath getNormalizedPath(int code) throws IOException; /** * Returns true if this font contains a glyph for the given character code. Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java?rev=1755774&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java (added) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java Wed Aug 10 16:06:07 2016 @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.rendering; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType0Font; +import org.apache.pdfbox.pdmodel.font.PDVectorFont; + +/** + * A simple glyph outline cache. + * + * @author John Hewson + */ +final class GlyphCache +{ + private static final Log LOG = LogFactory.getLog(GlyphCache.class); + + private final PDVectorFont font; + private final Map<Integer, GeneralPath> cache = new HashMap<Integer, GeneralPath>(); + + public GlyphCache(PDVectorFont font) + { + this.font = font; + } + + public void put(int code, GeneralPath path) + { + cache.put(code, path); + } + + public GeneralPath getPathForCharacterCode(int code) + { + GeneralPath path = cache.get(code); + if (path != null) + { + return path; + } + + try + { + if (!font.hasGlyph(code)) + { + String fontName = ((PDFont)font).getName(); + if (font instanceof PDType0Font) + { + int cid = ((PDType0Font) font).codeToCID(code); + String cidHex = String.format("%04x", cid); + LOG.warn("No glyph for " + code + " (CID " + cidHex + ") in font " + fontName); + } + else + { + LOG.warn("No glyph for " + code + " in font " + fontName); + } + } + + path = font.getNormalizedPath(code); + cache.put(code, path); + return path; + } + catch (IOException e) + { + // todo: escalate this error? + LOG.error("Glyph rendering failed", e); + return new GeneralPath(); + } + } +} Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1755774&r1=1755773&r2=1755774&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Wed Aug 10 16:06:07 2016 @@ -47,13 +47,8 @@ import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.function.PDFunction; -import org.apache.pdfbox.pdmodel.font.PDCIDFontType0; -import org.apache.pdfbox.pdmodel.font.PDCIDFontType2; import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont; -import org.apache.pdfbox.pdmodel.font.PDType0Font; -import org.apache.pdfbox.pdmodel.font.PDType1CFont; -import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.PDVectorFont; import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern; import org.apache.pdfbox.pdmodel.graphics.blend.SoftMaskPaint; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; @@ -92,26 +87,21 @@ public class PageDrawer extends PDFGraph // parent document renderer - note: this is needed for not-yet-implemented resource caching private final PDFRenderer renderer; - + // glyph caches + private final Map<PDFont, GlyphCache> glyphCaches = new HashMap<PDFont, GlyphCache>(); // the graphics device to draw to, xform is the initial transform of the device (i.e. DPI) private Graphics2D graphics; private AffineTransform xform; - // the page box to draw (usually the crop box but may be another) private PDRectangle pageSize; - // clipping winding rule used for the clipping path private int clipWindingRule = -1; private GeneralPath linePath = new GeneralPath(); - // last clipping path private Area lastClip; - // buffered clipping area for text being drawn private Area textClippingArea; - - // glyph cache - private final Map<PDFont, Glyph2D> fontGlyph2D = new HashMap<PDFont, Glyph2D>(); + /** * Constructor. @@ -330,27 +320,41 @@ public class PageDrawer extends PDFGraph AffineTransform at = textRenderingMatrix.createAffineTransform(); at.concatenate(font.getFontMatrix().createAffineTransform()); - Glyph2D glyph2D = createGlyph2D(font); - drawGlyph2D(glyph2D, font, code, displacement, at); + // create cache if it does not exist + PDVectorFont vectorFont = ((PDVectorFont)font); + GlyphCache cache = glyphCaches.get(font); + if (cache == null) + { + cache = new GlyphCache(vectorFont); + glyphCaches.put(font, cache); + } + + // cache glyph path if is not already cache + GeneralPath path = cache.getPathForCharacterCode(code); + if (path == null) + { + path = vectorFont.getNormalizedPath(code); + cache.put(code, path); + } + + drawGlyph(path, font, code, displacement, at); } /** * Render the font using the Glyph2D interface. * - * @param glyph2D the Glyph2D implementation provided a GeneralPath for each glyph + * @param path the Glyph2D implementation provided a GeneralPath for each glyph * @param font the font * @param code character code * @param displacement the glyph's displacement (advance) * @param at the transformation * @throws IOException if something went wrong */ - private void drawGlyph2D(Glyph2D glyph2D, PDFont font, int code, Vector displacement, - AffineTransform at) throws IOException + private void drawGlyph(GeneralPath path, PDFont font, int code, Vector displacement, AffineTransform at) throws IOException { PDGraphicsState state = getGraphicsState(); RenderingMode renderingMode = state.getTextState().getRenderingMode(); - - GeneralPath path = glyph2D.getPathForCharacterCode(code); + if (path != null) { // stretch non-embedded glyph if it does not match the width contained in the PDF @@ -391,72 +395,7 @@ public class PageDrawer extends PDFGraph } } } - - /** - * Provide a Glyph2D for the given font. - * - * @param font the font - * @return the implementation of the Glyph2D interface for the given font - * @throws IOException if something went wrong - */ - private Glyph2D createGlyph2D(PDFont font) throws IOException - { - Glyph2D glyph2D = fontGlyph2D.get(font); - // Is there already a Glyph2D for the given font? - if (glyph2D != null) - { - return glyph2D; - } - - if (font instanceof PDTrueTypeFont) - { - PDTrueTypeFont ttfFont = (PDTrueTypeFont)font; - glyph2D = new TTFGlyph2D(ttfFont); // TTF is never null - } - else if (font instanceof PDType1Font) - { - PDType1Font pdType1Font = (PDType1Font)font; - glyph2D = new Type1Glyph2D(pdType1Font); // T1 is never null - } - else if (font instanceof PDType1CFont) - { - PDType1CFont type1CFont = (PDType1CFont)font; - glyph2D = new Type1Glyph2D(type1CFont); - } - else if (font instanceof PDType0Font) - { - PDType0Font type0Font = (PDType0Font) font; - if (type0Font.getDescendantFont() instanceof PDCIDFontType2) - { - glyph2D = new TTFGlyph2D(type0Font); // TTF is never null - } - else if (type0Font.getDescendantFont() instanceof PDCIDFontType0) - { - // a Type0 CIDFont contains CFF font - PDCIDFontType0 cidType0Font = (PDCIDFontType0)type0Font.getDescendantFont(); - glyph2D = new CIDType0Glyph2D(cidType0Font); // todo: could be null (need incorporate fallback) - } - } - else - { - throw new IllegalStateException("Bad font type: " + font.getClass().getSimpleName()); - } - - // cache the Glyph2D instance - if (glyph2D != null) - { - fontGlyph2D.put(font, glyph2D); - } - - if (glyph2D == null) - { - // todo: make sure this never happens - throw new UnsupportedOperationException("No font for " + font.getName()); - } - - return glyph2D; - } - + @Override public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) { @@ -968,14 +907,6 @@ public class PageDrawer extends PDFGraph } } - private static class AnnotationBorder - { - private float[] dashArray = null; - private boolean underline = false; - private float width = 0; - private PDColor color; - } - // return border info. BorderStyle must be provided as parameter because // method is not available in the base class private AnnotationBorder getAnnotationBorder(PDAnnotation annotation, @@ -1034,7 +965,7 @@ public class PageDrawer extends PDFGraph } return ab; } - + private void drawAnnotationLinkBorder(PDAnnotationLink link) throws IOException { AnnotationBorder ab = getAnnotationBorder(link, link.getBorderStyle()); @@ -1157,6 +1088,14 @@ public class PageDrawer extends PDFGraph graphics.setTransform(prev); } + private static class AnnotationBorder + { + private float[] dashArray = null; + private boolean underline = false; + private float width = 0; + private PDColor color; + } + /** * Transparency group. **/