summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Hennebert <vhennebert@apache.org>2010-06-02 10:55:56 +0000
committerVincent Hennebert <vhennebert@apache.org>2010-06-02 10:55:56 +0000
commit0c11c0d32561d68c97d9bafcd8e5d823558419d8 (patch)
tree096cf4f99fc436227c5c83761e16507fd554c10d
parenta40acfafc3c7ba3d528c56831e387a1f5141044c (diff)
downloadxmlgraphics-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.java11
-rw-r--r--src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java1
-rw-r--r--src/java/org/apache/fop/render/ps/PSFontUtils.java102
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();
}