diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2010-06-02 10:55:56 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2010-06-02 10:55:56 +0000 |
commit | 0c11c0d32561d68c97d9bafcd8e5d823558419d8 (patch) | |
tree | 096cf4f99fc436227c5c83761e16507fd554c10d | |
parent | a40acfafc3c7ba3d528c56831e387a1f5141044c (diff) | |
download | xmlgraphics-fop-0c11c0d32561d68c97d9bafcd8e5d823558419d8.tar.gz xmlgraphics-fop-0c11c0d32561d68c97d9bafcd8e5d823558419d8.zip |
Added support for full embedding of TrueType font in PostScript, with encoding forced to WinAnsi.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@950488 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | src/java/org/apache/fop/fonts/SingleByteFont.java | 11 | ||||
-rw-r--r-- | src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java | 1 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSFontUtils.java | 102 |
3 files changed, 112 insertions, 2 deletions
diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index fb4725bd4..14cba4815 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -44,6 +44,7 @@ public class SingleByteFont extends CustomFont { //Map<Character, UnencodedCharacter> private List additionalEncodings; + private List cmaps; /** * Main constructor. @@ -334,5 +335,15 @@ public class SingleByteFont extends CustomFont { } } + /** TODO remove */ + public void setCMaps(List cmaps) { + this.cmaps = cmaps; + } + + /** TODO remove */ + public List getCMaps() { + return cmaps; + } + } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 405a25f9e..df8cce1b2 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -163,6 +163,7 @@ public class TTFFontLoader extends FontLoader { singleFont.setEncoding(ttf.getCharSetName()); returnFont.setFirstChar(ttf.getFirstChar()); returnFont.setLastChar(ttf.getLastChar()); + singleFont.setCMaps(ttf.getCMaps()); copyWidthsSingleByte(ttf); } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index a29210b41..7b359b176 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -23,8 +23,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; @@ -37,6 +40,7 @@ import org.apache.xmlgraphics.ps.DSCConstants; import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSResource; import org.apache.xmlgraphics.ps.dsc.ResourceTracker; +import org.apache.xmlgraphics.util.io.ASCIIHexOutputStream; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CustomFont; @@ -47,6 +51,7 @@ import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; +import org.apache.fop.fonts.truetype.TTFCmapEntry; /** * Utility code for font handling in PostScript. @@ -196,7 +201,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { public static void embedFont(PSGenerator gen, Typeface tf, PSResource fontRes) throws IOException { boolean embeddedFont = false; - if (FontType.TYPE1 == tf.getFontType()) { + FontType fontType = tf.getFontType(); + if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE) { if (tf instanceof CustomFont) { CustomFont cf = (CustomFont)tf; if (isEmbeddable(cf)) { @@ -204,7 +210,11 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (in != null) { gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, fontRes); - embedType1Font(gen, in); + if (fontType == FontType.TYPE1) { + embedType1Font(gen, in); + } else { + embedTrueTypeFont(gen, (SingleByteFont) tf, in); + } gen.writeDSCComment(DSCConstants.END_RESOURCE); gen.getResourceTracker().registerSuppliedResource(fontRes); embeddedFont = true; @@ -221,6 +231,94 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } } + private static void embedTrueTypeFont(PSGenerator gen, + SingleByteFont font, InputStream fontStream) throws IOException { + /* See Adobe Technical Note #5012, "The Type 42 Font Format Specification" */ + gen.commentln("%!PS-TrueTypeFont-65536-65536-1"); // TODO TrueType & font versions + gen.writeln("11 dict begin"); + gen.write("/FontName /"); + gen.write(font.getFontName()); + gen.writeln(" def"); + gen.writeln("/Encoding 256 array"); + gen.writeln("0 1 255{1 index exch/.notdef put}for"); + Set glyphs = new HashSet(); + for (int i = 0; i < Glyphs.WINANSI_ENCODING.length; i++) { + gen.write("dup "); + gen.write(Integer.toString(i)); + gen.write(" /"); + String glyphName = Glyphs.charToGlyphName(Glyphs.WINANSI_ENCODING[i]); + if (glyphName.equals("")) { + gen.write(Glyphs.NOTDEF); + } else { + glyphs.add(glyphName); + gen.write(glyphName); + } + gen.writeln(" put"); + } + gen.writeln("readonly def"); + gen.writeln("/PaintType 0 def"); + gen.writeln("/FontMatrix [1 0 0 1 0 0] def"); + int[] bbox = font.getFontBBox(); + gen.write("/FontBBox["); + for (int i = 0; i < 4; i++) { + gen.write(" "); + gen.write(Integer.toString(bbox[i])); + } + gen.writeln(" ] def"); + gen.writeln("/FontType 42 def"); + gen.write("/sfnts["); + /* + * Store the font file in an array of hex-encoded strings. Strings are limited to + * 65535 characters, string will start with a newline, 2 characters are needed to + * hex-encode each byte, one newline character will be added every 40 bytes, each + * string should start at a 4-byte boundary + * => buffer size = floor((65535 - 1) * 40 / 81 / 4) * 4 + * TODO this is not robust: depends on how often ASCIIHexOutputStream adds a newline + */ + // TODO does not follow Technical Note #5012's requirements: + // "strings must begin at TrueType table boundaries, or at individual glyph + // boundaries within the glyf table." + // There may be compatibility issues with older PostScript interpreters + byte[] buffer = new byte[32360]; + int readCount; + while ((readCount = fontStream.read(buffer)) > 0) { + ASCIIHexOutputStream hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); + gen.writeln("<"); + hexOut.write(buffer, 0, readCount); + gen.write("> "); + } + gen.writeln("]def"); + gen.write("/CharStrings "); + gen.write(Integer.toString(glyphs.size() + 1)); + gen.writeln(" dict dup begin"); + gen.write("/"); + gen.write(Glyphs.NOTDEF); + gen.writeln(" 0 def"); // TODO always glyph index 0? + // TODO ugly and temporary, until CID is implemented + List cmaps = font.getCMaps(); + for (Iterator iter = glyphs.iterator(); iter.hasNext();) { + String glyphName = (String) iter.next(); + gen.write("/"); + gen.write(glyphName); + gen.write(" "); + gen.write(Integer.toString(getGlyphIndex(glyphName, cmaps))); + gen.writeln(" def"); + } + gen.writeln("end readonly def"); + gen.writeln("FontName currentdict end definefont pop"); + } + + private static int getGlyphIndex(String glyphName, List cmaps) { + char c = Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0); + for (Iterator iter = cmaps.iterator(); iter.hasNext();) { + TTFCmapEntry cmap = (TTFCmapEntry) iter.next(); + if (cmap.getUnicodeStart() <= c && c <= cmap.getUnicodeEnd()) { + return cmap.getGlyphStartIndex() + c - cmap.getUnicodeStart(); + } + } + return 0; + } + private static boolean isEmbeddable(CustomFont font) { return font.isEmbeddable(); } |