]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-2642: Add optimize-resources for IF to PCL
authorSimon Steiner <ssteiner@apache.org>
Mon, 15 Aug 2016 14:15:27 +0000 (14:15 +0000)
committerSimon Steiner <ssteiner@apache.org>
Mon, 15 Aug 2016 14:15:27 +0000 (14:15 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1756387 13f79535-47bb-0310-9956-ffa450edef68

22 files changed:
fop-core/src/main/java/org/apache/fop/fonts/CIDSubset.java
fop-core/src/main/java/org/apache/fop/render/pcl/Java2DRendererOption.java
fop-core/src/main/java/org/apache/fop/render/pcl/PCLDocumentHandler.java
fop-core/src/main/java/org/apache/fop/render/pcl/PCLGenerator.java
fop-core/src/main/java/org/apache/fop/render/pcl/PCLPainter.java
fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfig.java
fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java
fop-core/src/main/java/org/apache/fop/render/pcl/PCLRenderingUtil.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java
fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java
fop-core/src/test/java/org/apache/fop/render/pcl/PCLPainterTestCase.java
fop-core/src/test/java/org/apache/fop/render/pcl/fonts/MockPCLTTFFontReader.java
fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtilTestCase.java
fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactoryTestCase.java
fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLTTFFontReaderTestCase.java
fop-core/src/test/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriterTestCase.java

index 01b8495f8037994a54eea9eef2c6d4768a27fc61..e0fbdd6c24a5d92c1a9b76f344ce96506f5999fb 100644 (file)
@@ -22,6 +22,7 @@ package org.apache.fop.fonts;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import org.apache.fop.util.CharUtilities;
@@ -40,7 +41,7 @@ public class CIDSubset implements CIDSet {
     /**
      * usedGlyphs contains orginal, new glyph index (glyph index -> char selector)
      */
-    private Map<Integer, Integer> usedGlyphs = new HashMap<Integer, Integer>();
+    private Map<Integer, Integer> usedGlyphs = new LinkedHashMap<Integer, Integer>();
 
     /**
      * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index)
index 9ec0b779bb63e42198df2f1a9485eec70a0a1b5f..7a0a4a77e0d5c234f9d19b0bbb7a9f99289b56f7 100644 (file)
@@ -28,6 +28,7 @@ public enum Java2DRendererOption implements RendererConfigOption {
     RENDERING_MODE("rendering", PCLRenderingMode.class),
     TEXT_RENDERING("text-rendering", Boolean.class),
     DISABLE_PJL("disable-pjl", Boolean.class),
+    OPTIMIZE_RESOURCES("optimize-resources", Boolean.class),
     MODE_COLOR("color", Boolean.class);
 
     private final String name;
index 66655a721c0c4825f6b4a4c6c386de99e1d357d8..a4492b175214128a867bf8db29236f4e8c8e4bf8 100644 (file)
@@ -25,16 +25,26 @@ import java.awt.Graphics2D;
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Map;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.xmlgraphics.io.TempResourceURIGenerator;
 import org.apache.xmlgraphics.util.UnitConv;
 
 import org.apache.fop.apps.FopFactoryConfig;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.Typeface;
 import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
 import org.apache.fop.render.intermediate.IFContext;
 import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
@@ -44,6 +54,7 @@ import org.apache.fop.render.java2d.Java2DPainter;
 import org.apache.fop.render.java2d.Java2DUtil;
 import org.apache.fop.render.pcl.PCLRendererConfig.PCLRendererConfigParser;
 import org.apache.fop.render.pcl.extensions.PCLElementMapping;
+import org.apache.fop.render.pcl.fonts.PCLSoftFontManager;
 
 /**
  * {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation
@@ -55,6 +66,10 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
     /** logging instance */
     private static Log log = LogFactory.getLog(PCLDocumentHandler.class);
 
+    /** the temporary file in case of two-pass processing */
+    private URI tempURI;
+    private static final TempResourceURIGenerator TEMP_URI_GENERATOR = new TempResourceURIGenerator("pcl-optimize");
+
     /** Utility class for handling all sorts of peripheral tasks around PCL generation. */
     protected PCLRenderingUtil pclUtil;
 
@@ -127,7 +142,15 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
     public void startDocument() throws IFException {
         super.startDocument();
         try {
-            this.gen = new PCLGenerator(this.outputStream, getResolution());
+            final OutputStream out;
+            if (pclUtil.isOptimizeResources()) {
+                tempURI = TEMP_URI_GENERATOR.generate();
+                out = new BufferedOutputStream(getUserAgent().getResourceResolver().getOutputStream(tempURI));
+            } else {
+                out = this.outputStream;
+            }
+
+            this.gen = new PCLGenerator(out, getResolution());
             this.gen.setDitheringQuality(pclUtil.getDitheringQuality());
 
             if (!pclUtil.isPJLDisabled()) {
@@ -161,12 +184,47 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
             if (!pclUtil.isPJLDisabled()) {
                 gen.universalEndOfLanguage();
             }
+
+            if (pclUtil.isOptimizeResources()) {
+                IOUtils.closeQuietly(gen.getOutputStream());
+                rewritePCLFile();
+            }
         } catch (IOException ioe) {
             throw new IFException("I/O error in endDocument()", ioe);
         }
         super.endDocument();
     }
 
+    private void rewritePCLFile() throws IOException {
+        InputStream in = new BufferedInputStream(getUserAgent().getResourceResolver().getResource(tempURI));
+        long offset = 0;
+        for (Map.Entry<PCLSoftFontManager, Map<Typeface, Long>> fontManagerMapEntry : gen.fontManagerMap.entrySet()) {
+            PCLSoftFontManager softFontManager = fontManagerMapEntry.getKey();
+            for (Map.Entry<Typeface, Long> fontEntry : fontManagerMapEntry.getValue().entrySet()) {
+                ByteArrayOutputStream fontData = softFontManager.makeSoftFont(fontEntry.getKey(), null);
+                long pos = fontEntry.getValue();
+                copy(in, pos - offset);
+                outputStream.write(fontData.toByteArray());
+                offset = pos;
+            }
+        }
+        copy(in, Long.MAX_VALUE);
+        this.outputStream.flush();
+        IOUtils.closeQuietly(in);
+    }
+
+    private void copy(InputStream is, long len) throws IOException {
+        while (len > 0) {
+            int bufsize = (int) Math.min(1024, len);
+            byte[] buf = new byte[bufsize];
+            if (is.read(buf) == -1) {
+                return;
+            }
+            outputStream.write(buf);
+            len -= bufsize;
+        }
+    }
+
     /** {@inheritDoc} */
     public void startPageSequence(String id) throws IFException {
         //nop
index 589779ad9f3579e401fa68e04e0e5bc1ef6e5cdb..6a4f3215e053ca689d2bb4f721fd163bb18618ad 100644 (file)
@@ -39,13 +39,20 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Locale;
+import java.util.Map;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.io.output.CountingOutputStream;
 
 import org.apache.xmlgraphics.util.UnitConv;
 
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.render.pcl.fonts.PCLFontReader;
+import org.apache.fop.render.pcl.fonts.PCLSoftFontManager;
 import org.apache.fop.util.bitmap.BitmapImageUtil;
 import org.apache.fop.util.bitmap.DitherUtil;
 
@@ -68,7 +75,10 @@ public class PCLGenerator {
     private final DecimalFormat df2 = new DecimalFormat("0.##", symbols);
     private final DecimalFormat df4 = new DecimalFormat("0.####", symbols);
 
-    private final OutputStream out;
+    private final CountingOutputStream out;
+    protected Map<Typeface, PCLFontReader> fontReaderMap = new HashMap<Typeface, PCLFontReader>();
+    protected Map<PCLSoftFontManager, Map<Typeface, Long>> fontManagerMap
+            = new LinkedHashMap<PCLSoftFontManager, Map<Typeface, Long>>();
 
     private boolean currentSourceTransparency = true;
     private boolean currentPatternTransparency = true;
@@ -87,7 +97,7 @@ public class PCLGenerator {
      * @param out the OutputStream to write the PCL stream to
      */
     public PCLGenerator(OutputStream out) {
-        this.out = out;
+        this.out = new CountingOutputStream(out);
     }
 
     /**
@@ -110,6 +120,16 @@ public class PCLGenerator {
         this.maxBitmapResolution = maxResolution;
     }
 
+    public void addFont(PCLSoftFontManager sfManager, Typeface font) {
+        if (!fontManagerMap.containsKey(sfManager)) {
+            fontManagerMap.put(sfManager, new LinkedHashMap<Typeface, Long>());
+        }
+        Map<Typeface, Long> fonts = fontManagerMap.get(sfManager);
+        if (!fonts.containsKey(font)) {
+            fonts.put(font, out.getByteCount());
+        }
+    }
+
     /** @return the OutputStream that this generator writes to */
     public OutputStream getOutputStream() {
         return this.out;
index 65e996d08db558d8408d0fdfcac1b3d3eafa4a35..60d6eb89fd725547a3c29596ebef7e2ccb1e1d97 100644 (file)
@@ -85,8 +85,7 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
 
     private Stack<GraphicContext> graphicContextStack = new Stack<GraphicContext>();
     private GraphicContext graphicContext = new GraphicContext();
-
-    private PCLSoftFontManager sfManager = new PCLSoftFontManager();
+    private PCLSoftFontManager sfManager;
 
     /**
      * Main constructor.
@@ -338,12 +337,20 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
             } else {
                 // TrueType conversion to a soft font (PCL 5 Technical Reference - Chapter 11)
                 if (!drawAsBitmaps && isTrueType(tf)) {
-                    boolean madeSF = false;
-                    if (sfManager.getSoftFont(tf, text) == null) {
-                        madeSF = true;
-                        ByteArrayOutputStream baos = sfManager.makeSoftFont(tf);
+                    if (sfManager == null) {
+                        sfManager = new PCLSoftFontManager(gen.fontReaderMap);
+                    }
+                    if (getPCLUtil().isOptimizeResources() || sfManager.getSoftFont(tf, text) == null) {
+                        for (char c : text.toCharArray()) {
+                            tf.mapChar(c);
+                        }
+                        ByteArrayOutputStream baos = sfManager.makeSoftFont(tf, text);
                         if (baos != null) {
-                            gen.writeBytes(baos.toByteArray());
+                            if (getPCLUtil().isOptimizeResources()) {
+                                gen.addFont(sfManager, tf);
+                            } else {
+                                gen.writeBytes(baos.toByteArray());
+                            }
                         }
                     }
                     String formattedSize = gen.formatDouble2(state.getFontSize() / 1000.0);
index 30429a7c5210647d643e81436ee6b5780d68ec8e..06aebba715dca10cb4212f5f885c907b267a956f 100644 (file)
@@ -34,6 +34,7 @@ import org.apache.fop.render.RendererConfig;
 
 import static org.apache.fop.render.pcl.Java2DRendererOption.DISABLE_PJL;
 import static org.apache.fop.render.pcl.Java2DRendererOption.MODE_COLOR;
+import static org.apache.fop.render.pcl.Java2DRendererOption.OPTIMIZE_RESOURCES;
 import static org.apache.fop.render.pcl.Java2DRendererOption.RENDERING_MODE;
 import static org.apache.fop.render.pcl.Java2DRendererOption.TEXT_RENDERING;
 
@@ -71,6 +72,10 @@ public final class PCLRendererConfig implements RendererConfig {
         return getParam(MODE_COLOR, Boolean.class);
     }
 
+    public Boolean isOptimizeResources() {
+        return getParam(OPTIMIZE_RESOURCES, Boolean.class);
+    }
+
     private <T> T getParam(Java2DRendererOption option, Class<T> type) {
         assert option.getType().equals(type);
         return type.cast(params.get(option));
@@ -124,6 +129,8 @@ public final class PCLRendererConfig implements RendererConfig {
                 }
                 config.setParam(DISABLE_PJL,
                         cfg.getChild(DISABLE_PJL.getName()).getValueAsBoolean(false));
+                config.setParam(OPTIMIZE_RESOURCES,
+                        cfg.getChild(OPTIMIZE_RESOURCES.getName()).getValueAsBoolean(false));
             }
         }
 
index 7a92b7408fb29cfcea7285a312b12f5f1e4a6604..1641055dd9718af93040bfddd99eb40633e1796e 100644 (file)
@@ -70,6 +70,9 @@ public class PCLRendererConfigurator extends PrintRendererConfigurator {
         if (config.isColorEnabled() != null) {
             pclUtil.setColorEnabled(config.isColorEnabled());
         }
+        if (config.isOptimizeResources() != null) {
+            pclUtil.setOptimizeResources(config.isOptimizeResources());
+        }
     }
 
     @Override
index 674605bdec5fe173352a2c9d5167cc661b344c35..0c4fb522fd82edfee5edc273c86acdb8665c409c 100644 (file)
@@ -51,6 +51,7 @@ public class PCLRenderingUtil {
     private float ditheringQuality = 0.5f;
 
     private boolean useColor;
+    private boolean optimizeResources;
 
     /**
      * Controls whether the generation of PJL commands gets disabled.
@@ -228,4 +229,12 @@ public class PCLRenderingUtil {
         return transPoint;
     }
 
+    public boolean isOptimizeResources() {
+        return optimizeResources;
+    }
+
+    public void setOptimizeResources(boolean b) {
+        optimizeResources = b;
+    }
+
 }
index 1b9382f7b883f88cd8b76a49b97b8a96d72360d7..3a5d68602aec626645588cf284f53bed54cbddc7 100644 (file)
@@ -23,13 +23,16 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
 
-public class PCLByteWriterUtil {
+public final class PCLByteWriterUtil {
 
-    public byte[] padBytes(byte[] in, int length) {
+    private PCLByteWriterUtil() {
+    }
+
+    public static byte[] padBytes(byte[] in, int length) {
         return padBytes(in, length, 0);
     }
 
-    public byte[] padBytes(byte[] in, int length, int value) {
+    public static byte[] padBytes(byte[] in, int length, int value) {
         byte[] out = new byte[length];
         for (int i = 0; i < length; i++) {
             if (i < in.length) {
@@ -41,21 +44,21 @@ public class PCLByteWriterUtil {
         return out;
     }
 
-    public byte[] signedInt(int s) {
+    public static byte[] signedInt(int s) {
         byte b1 = (byte) (s >> 8);
         byte b2 = (byte) s;
         return new byte[]{b1, b2};
     }
 
-    public byte signedByte(int s) {
+    public static byte signedByte(int s) {
         return (byte) s;
     }
 
-    public byte[] unsignedLongInt(int s) {
+    public static byte[] unsignedLongInt(int s) {
         return unsignedLongInt((long) s);
     }
 
-    public byte[] unsignedLongInt(long s) {
+    public static byte[] unsignedLongInt(long s) {
         byte b1 = (byte) ((s >> 24) & 0xff);
         byte b2 = (byte) ((s >> 16) & 0xff);
         byte b3 = (byte) ((s >> 8) & 0xff);
@@ -63,17 +66,17 @@ public class PCLByteWriterUtil {
         return new byte[]{b1, b2, b3, b4};
     }
 
-    public byte[] unsignedInt(int s) {
+    public static byte[] unsignedInt(int s) {
         byte b1 = (byte) ((s >> 8) & 0xff);
         byte b2 = (byte) (s & 0xff);
         return new byte[]{b1, b2};
     }
 
-    public int unsignedByte(int b) {
+    public static int unsignedByte(int b) {
         return (byte) b & 0xFF;
     }
 
-    public int maxPower2(int value) {
+    public static int maxPower2(int value) {
         int test = 2;
         while (test < value) {
             test *= 2;
@@ -81,11 +84,11 @@ public class PCLByteWriterUtil {
         return test;
     }
 
-    public int log(int x, int base) {
+    public static int log(int x, int base) {
         return (int) (Math.log(x) / Math.log(base));
     }
 
-    public byte[] toByteArray(int[] s) {
+    public static byte[] toByteArray(int[] s) {
         byte[] values = new byte[s.length];
         for (int i = 0; i < s.length; i++) {
             values[i] = (byte) s[i];
@@ -93,7 +96,7 @@ public class PCLByteWriterUtil {
         return values;
     }
 
-    public byte[] insertIntoArray(int index, byte[] insertTo, byte[] data) throws IOException {
+    public static byte[] insertIntoArray(int index, byte[] insertTo, byte[] data) throws IOException {
         byte[] preBytes = Arrays.copyOf(insertTo, index);
         byte[] postBytes = Arrays.copyOfRange(insertTo, index, insertTo.length);
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -103,7 +106,7 @@ public class PCLByteWriterUtil {
         return baos.toByteArray();
     }
 
-    public byte[] updateDataAtLocation(byte[] data, byte[] update, int offset) {
+    public static byte[] updateDataAtLocation(byte[] data, byte[] update, int offset) {
         int count = 0;
         for (int i = offset; i < offset + update.length; i++) {
             data[i] = update[count++];
@@ -116,7 +119,7 @@ public class PCLByteWriterUtil {
      * @param cmd the command (without the ESCAPE character)
      * @throws IOException In case of an I/O error
      */
-    public byte[] writeCommand(String cmd) throws IOException {
+    public static byte[] writeCommand(String cmd) throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         baos.write(27); // ESC
         baos.write(cmd.getBytes("US-ASCII"));
index c275084dcab31cd3df950277987e608bfc40102e..3c4053c72ffcb09aeb56f8b6a6e7bd195ed6940b 100644 (file)
@@ -31,18 +31,15 @@ public class PCLCharacterDefinition {
     private boolean hasContinuation;
     private PCLCharacterFormat charFormat;
     private PCLCharacterClass charClass;
-    private PCLByteWriterUtil pclByteWriter;
     private List<PCLCharacterDefinition> composites;
     private boolean isComposite;
 
     public PCLCharacterDefinition(int charCode, PCLCharacterFormat charFormat,
-            PCLCharacterClass charClass, byte[] glyfData, PCLByteWriterUtil pclByteWriter,
-            boolean isComposite) {
+            PCLCharacterClass charClass, byte[] glyfData, boolean isComposite) {
         this.charCode = charCode;
         this.charFormat = charFormat;
         this.charClass = charClass;
         this.glyfData = glyfData;
-        this.pclByteWriter = pclByteWriter;
         this.isComposite = isComposite;
         // Glyph Data + (Descriptor Size) + (Character Data Size) + (Glyph ID) must
         // be less than 32767 otherwise it will result in a continuation structure.
@@ -52,11 +49,11 @@ public class PCLCharacterDefinition {
     }
 
     public byte[] getCharacterCommand() throws IOException {
-        return pclByteWriter.writeCommand(String.format("*c%dE", (isComposite) ? 65535 : charCode));
+        return PCLByteWriterUtil.writeCommand(String.format("*c%dE", (isComposite) ? 65535 : charCode));
     }
 
     public byte[] getCharacterDefinitionCommand() throws IOException {
-        return pclByteWriter.writeCommand(String.format("(s%dW", 10 + glyfData.length));
+        return PCLByteWriterUtil.writeCommand(String.format("(s%dW", 10 + glyfData.length));
     }
 
     public byte[] getData() throws IOException {
@@ -89,12 +86,12 @@ public class PCLCharacterDefinition {
     }
 
     private void writeCharacterDescriptorHeader(int continuation, ByteArrayOutputStream baos) throws IOException {
-        baos.write(pclByteWriter.unsignedByte(charFormat.getValue()));
+        baos.write(PCLByteWriterUtil.unsignedByte(charFormat.getValue()));
         baos.write(continuation);
-        baos.write(pclByteWriter.unsignedByte(2)); // Descriptor size (from this byte to character data)
-        baos.write(pclByteWriter.unsignedByte(charClass.getValue()));
-        baos.write(pclByteWriter.unsignedInt(glyfData.length + 4));
-        baos.write(pclByteWriter.unsignedInt(charCode));
+        baos.write(PCLByteWriterUtil.unsignedByte(2)); // Descriptor size (from this byte to character data)
+        baos.write(PCLByteWriterUtil.unsignedByte(charClass.getValue()));
+        baos.write(PCLByteWriterUtil.unsignedInt(glyfData.length + 4));
+        baos.write(PCLByteWriterUtil.unsignedInt(charCode));
     }
 
     public void addCompositeGlyph(PCLCharacterDefinition composite) {
index df04371e0d7d7c098f99b715a6bcfea4c2d4dc01..51e067980cd4f4bf33a509f1017d5f91040dfd55 100644 (file)
@@ -27,7 +27,6 @@ import org.apache.fop.fonts.truetype.OpenFont;
 public abstract class PCLCharacterWriter {
 
     protected PCLSoftFont font;
-    protected PCLByteWriterUtil pclByteWriter;
     protected OpenFont openFont;
     protected FontFileReader fontReader;
 
@@ -35,7 +34,6 @@ public abstract class PCLCharacterWriter {
         this.font = font;
         openFont = font.getOpenFont();
         fontReader = font.getReader();
-        pclByteWriter = new PCLByteWriterUtil();
     }
 
     public abstract byte[] writeCharacterDefinitions(String text) throws IOException;
index 6bd5192acc87a74ac5cc12b4f59cef9e87bbf6c4..b0b95f34b47da407000b6167158855087b910b4c 100644 (file)
@@ -31,12 +31,10 @@ import org.apache.fop.fonts.truetype.OpenFont;
 public abstract class PCLFontReader {
 
     protected Typeface typeface;
-    protected PCLByteWriterUtil pclByteWriter;
     protected CustomFont font;
 
-    public PCLFontReader(Typeface font, PCLByteWriterUtil pclByteWriter) {
+    public PCLFontReader(Typeface font) {
         this.typeface = font;
-        this.pclByteWriter = pclByteWriter;
     }
 
     public void setFont(CustomFont mbFont) {
@@ -81,6 +79,7 @@ public abstract class PCLFontReader {
     public abstract int getMasterUnderlineThickness() throws IOException;
     public abstract int getFontScalingTechnology();
     public abstract int getVariety();
+    public abstract Map<Integer, Integer> scanMtxCharacters() throws IOException;
 
     /** Segmented Font Data **/
     public abstract List<PCLFontSegment> getFontSegments(Map<Character, Integer> mappedGlyphs)
index 15c4e8d548d544708c64e67f7f06acf7f8c8bcb1..aced97a99476f66bf267f2a0a06fc3cf85b07cae 100644 (file)
@@ -31,19 +31,12 @@ import org.apache.fop.render.pcl.fonts.truetype.PCLTTFFontReader;
 
 public final class PCLFontReaderFactory {
 
-    private PCLByteWriterUtil pclByteWriter;
-
-    private PCLFontReaderFactory(PCLByteWriterUtil pclByteWriter) {
-        this.pclByteWriter = pclByteWriter;
-    }
-
-    public static PCLFontReaderFactory getInstance(PCLByteWriterUtil pclByteWriter) {
-        return new PCLFontReaderFactory(pclByteWriter);
+    private PCLFontReaderFactory() {
     }
 
-    public PCLFontReader createInstance(Typeface font) throws IOException {
+    public static PCLFontReader createInstance(Typeface font) throws IOException {
         if (font.getFontType() == FontType.TRUETYPE || isCIDType2(font)) {
-            return new PCLTTFFontReader(font, pclByteWriter);
+            return new PCLTTFFontReader(font);
         }
         // else if (font instanceof MultiByteFont && ((MultiByteFont) font).isOTFFile()) {
             // Placeholder for future Type 1 / OTF Soft font implementations e.g.
@@ -52,7 +45,7 @@ public final class PCLFontReaderFactory {
         return null;
     }
 
-    private boolean isCIDType2(Typeface font) {
+    private static boolean isCIDType2(Typeface font) {
         CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) font;
         CustomFont customFont = (CustomFont) fontMetrics.getRealFont();
 
index 621ea4f18ead54053ce240e57c220c99efd1d347..42616581efb71824b56b35314a3b83283c908262 100644 (file)
@@ -21,8 +21,10 @@ package org.apache.fop.render.pcl.fonts;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -32,35 +34,37 @@ import org.apache.fop.fonts.Typeface;
 import org.apache.fop.render.java2d.CustomFontMetricsMapper;
 
 public class PCLSoftFontManager {
-    private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    private Map<Typeface, PCLFontReader> fontReaderMap;
     private PCLFontReader fontReader;
-    private PCLByteWriterUtil pclByteWriter = new PCLByteWriterUtil();
     private List<PCLSoftFont> fonts = new ArrayList<PCLSoftFont>();
-    private PCLFontReaderFactory fontReaderFactory;
 
     private static final int SOFT_FONT_SIZE = 255;
 
-    public ByteArrayOutputStream makeSoftFont(Typeface font) throws IOException {
+    public PCLSoftFontManager(Map<Typeface, PCLFontReader> fontReaderMap) {
+        this.fontReaderMap = fontReaderMap;
+    }
+
+    public ByteArrayOutputStream makeSoftFont(Typeface font, String text) throws IOException {
         List<Map<Character, Integer>> mappedGlyphs = mapFontGlyphs(font);
-        if (fontReaderFactory == null) {
-            fontReaderFactory = PCLFontReaderFactory.getInstance(pclByteWriter);
+        if (!fontReaderMap.containsKey(font)) {
+            fontReaderMap.put(font, PCLFontReaderFactory.createInstance(font));
         }
-        fontReader = fontReaderFactory.createInstance(font);
-        initialize();
+        fontReader = fontReaderMap.get(font);
         if (mappedGlyphs.isEmpty()) {
             mappedGlyphs.add(new HashMap<Character, Integer>());
         }
         if (fontReader != null) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            PCLSoftFont softFont = null;
             for (Map<Character, Integer> glyphSet : mappedGlyphs) {
-                PCLSoftFont softFont = new PCLSoftFont(fonts.size() + 1, font,
-                        mappedGlyphs.get(0).size() != 0);
+                softFont = getSoftFont(font, text, mappedGlyphs, softFont);
                 softFont.setMappedChars(glyphSet);
-                assignFontID();
-                writeFontHeader(softFont.getMappedChars());
+                writeFontID(softFont.getFontID(), baos);
+                writeFontHeader(softFont.getMappedChars(), baos);
                 softFont.setCharacterOffsets(fontReader.getCharacterOffsets());
                 softFont.setOpenFont(fontReader.getFontFile());
                 softFont.setReader(fontReader.getFontFileReader());
-                fonts.add(softFont);
+                softFont.setMtxCharIndexes(fontReader.scanMtxCharacters());
             }
             return baos;
         } else {
@@ -68,6 +72,29 @@ public class PCLSoftFontManager {
         }
     }
 
+    private PCLSoftFont getSoftFont(Typeface font, String text, List<Map<Character, Integer>> mappedGlyphs,
+                                    PCLSoftFont last) {
+        if (text == null) {
+            Iterator<PCLSoftFont> fontIterator = fonts.iterator();
+            while (fontIterator.hasNext()) {
+                PCLSoftFont sftFont = fontIterator.next();
+                if (sftFont.getTypeface().equals(font)) {
+                    fontIterator.remove();
+                    return sftFont;
+                }
+            }
+        }
+        for (PCLSoftFont sftFont : fonts) {
+            if (sftFont.getTypeface().equals(font) && sftFont != last
+                    && (sftFont.getCharCount() + countNonMatches(sftFont, text)) < SOFT_FONT_SIZE) {
+                return sftFont;
+            }
+        }
+        PCLSoftFont f = new PCLSoftFont(fonts.size() + 1, font, mappedGlyphs.get(0).size() != 0);
+        fonts.add(f);
+        return f;
+    }
+
     private List<Map<Character, Integer>> mapFontGlyphs(Typeface tf) {
         List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>();
         if (tf instanceof CustomFontMetricsMapper) {
@@ -101,63 +128,59 @@ public class PCLSoftFontManager {
         return mappedGlyphs;
     }
 
-    private void initialize() {
-        baos.reset();
-    }
-
-    private void assignFontID() throws IOException {
-        baos.write(assignFontID(fonts.size() + 1));
+    private void writeFontID(int fontID, OutputStream os) throws IOException {
+        os.write(assignFontID(fontID));
     }
 
     public byte[] assignFontID(int fontID) throws IOException {
-        return pclByteWriter.writeCommand(String.format("*c%dD", fontID));
+        return PCLByteWriterUtil.writeCommand(String.format("*c%dD", fontID));
     }
 
-    private void writeFontHeader(Map<Character, Integer> mappedGlyphs) throws IOException {
+    private void writeFontHeader(Map<Character, Integer> mappedGlyphs, OutputStream os) throws IOException {
         ByteArrayOutputStream header = new ByteArrayOutputStream();
-        header.write(pclByteWriter.unsignedInt(fontReader.getDescriptorSize()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getHeaderFormat()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getFontType()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getStyleMSB()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getDescriptorSize()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getHeaderFormat()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getFontType()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getStyleMSB()));
         header.write(0); // Reserved
-        header.write(pclByteWriter.unsignedInt(fontReader.getBaselinePosition()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getCellWidth()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getCellHeight()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getOrientation()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getBaselinePosition()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getCellWidth()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getCellHeight()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getOrientation()));
         header.write(fontReader.getSpacing());
-        header.write(pclByteWriter.unsignedInt(fontReader.getSymbolSet()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getPitch()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getHeight()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getXHeight()));
-        header.write(pclByteWriter.signedByte(fontReader.getWidthType()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getStyleLSB()));
-        header.write(pclByteWriter.signedByte(fontReader.getStrokeWeight()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getTypefaceLSB()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getTypefaceMSB()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getSerifStyle()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getQuality()));
-        header.write(pclByteWriter.signedByte(fontReader.getPlacement()));
-        header.write(pclByteWriter.signedByte(fontReader.getUnderlinePosition()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getUnderlineThickness()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getTextHeight()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getTextWidth()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getFirstCode()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getLastCode()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getPitchExtended()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getHeightExtended()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getCapHeight()));
-        header.write(pclByteWriter.unsignedLongInt(fontReader.getFontNumber()));
-        header.write(pclByteWriter.padBytes(fontReader.getFontName().getBytes("US-ASCII"), 16, 32));
-        header.write(pclByteWriter.unsignedInt(fontReader.getScaleFactor()));
-        header.write(pclByteWriter.signedInt(fontReader.getMasterUnderlinePosition()));
-        header.write(pclByteWriter.unsignedInt(fontReader.getMasterUnderlineThickness()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getFontScalingTechnology()));
-        header.write(pclByteWriter.unsignedByte(fontReader.getVariety()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getSymbolSet()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getPitch()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getHeight()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getXHeight()));
+        header.write(PCLByteWriterUtil.signedByte(fontReader.getWidthType()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getStyleLSB()));
+        header.write(PCLByteWriterUtil.signedByte(fontReader.getStrokeWeight()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getTypefaceLSB()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getTypefaceMSB()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getSerifStyle()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getQuality()));
+        header.write(PCLByteWriterUtil.signedByte(fontReader.getPlacement()));
+        header.write(PCLByteWriterUtil.signedByte(fontReader.getUnderlinePosition()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getUnderlineThickness()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getTextHeight()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getTextWidth()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getFirstCode()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getLastCode()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getPitchExtended()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getHeightExtended()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getCapHeight()));
+        header.write(PCLByteWriterUtil.unsignedLongInt(fontReader.getFontNumber()));
+        header.write(PCLByteWriterUtil.padBytes(fontReader.getFontName().getBytes("US-ASCII"), 16, 32));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getScaleFactor()));
+        header.write(PCLByteWriterUtil.signedInt(fontReader.getMasterUnderlinePosition()));
+        header.write(PCLByteWriterUtil.unsignedInt(fontReader.getMasterUnderlineThickness()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getFontScalingTechnology()));
+        header.write(PCLByteWriterUtil.unsignedByte(fontReader.getVariety()));
 
         writeSegmentedFontData(header, mappedGlyphs);
 
-        baos.write(getFontHeaderCommand(header.size()));
-        baos.write(header.toByteArray());
+        os.write(getFontHeaderCommand(header.size()));
+        os.write(header.toByteArray());
     }
 
     private void writeSegmentedFontData(ByteArrayOutputStream header,
@@ -178,12 +201,12 @@ public class PCLSoftFontManager {
     }
 
     private byte[] getFontHeaderCommand(int headerSize) throws IOException {
-        return pclByteWriter.writeCommand(String.format(")s%dW", headerSize));
+        return PCLByteWriterUtil.writeCommand(String.format(")s%dW", headerSize));
     }
 
     private void writeFontSegment(ByteArrayOutputStream header, PCLFontSegment segment) throws IOException {
-        header.write(pclByteWriter.unsignedInt(segment.getIdentifier().getValue()));
-        header.write(pclByteWriter.unsignedInt(segment.getData().length));
+        header.write(PCLByteWriterUtil.unsignedInt(segment.getIdentifier().getValue()));
+        header.write(PCLByteWriterUtil.unsignedInt(segment.getData().length));
         header.write(segment.getData());
     }
 
index 41fefaaf00a73f7cc22fd5483d2e8d9db9f0e0f3..d09048bc025e6c47f26b260b1791bfa8256e1cbb 100644 (file)
@@ -44,7 +44,6 @@ public class PCLTTFCharacterWriter extends PCLCharacterWriter {
 
     public PCLTTFCharacterWriter(PCLSoftFont softFont) throws IOException {
         super(softFont);
-        softFont.setMtxCharIndexes(scanMtxCharacters());
     }
 
     @Override
@@ -70,25 +69,6 @@ public class PCLTTFCharacterWriter extends PCLCharacterWriter {
         baos.write(pclChar.getData());
     }
 
-    private Map<Integer, Integer> scanMtxCharacters() throws IOException {
-        Map<Integer, Integer> charMtxOffsets = new HashMap<Integer, Integer>();
-        List<OFMtxEntry> mtx = openFont.getMtx();
-        OFTableName glyfTag = OFTableName.GLYF;
-        if (openFont.seekTab(fontReader, glyfTag, 0)) {
-            for (int i = 1; i < mtx.size(); i++) {
-                OFMtxEntry entry = mtx.get(i);
-                int charCode = 0;
-                if (entry.getUnicodeIndex().size() > 0) {
-                    charCode = (Integer) entry.getUnicodeIndex().get(0);
-                } else {
-                    charCode = entry.getIndex();
-                }
-                charMtxOffsets.put(charCode, i);
-            }
-        }
-        return charMtxOffsets;
-    }
-
     private PCLCharacterDefinition getCharacterDefinition(int unicode) throws IOException {
         if (mtx == null) {
             mtx = openFont.getMtx();
@@ -112,7 +92,7 @@ public class PCLTTFCharacterWriter extends PCLCharacterWriter {
             PCLCharacterDefinition newChar = new PCLCharacterDefinition(
                     font.getCharCode((char) unicode),
                     PCLCharacterFormat.TrueType,
-                    PCLCharacterClass.TrueType, glyphData, pclByteWriter, false);
+                    PCLCharacterClass.TrueType, glyphData, false);
 
             // Handle composite character definitions
             GlyfTable glyfTable = new GlyfTable(fontReader, mtx.toArray(new OFMtxEntry[mtx.size()]),
@@ -123,7 +103,7 @@ public class PCLTTFCharacterWriter extends PCLCharacterWriter {
                     byte[] compositeData = getGlyphData(compositeIndex);
                     newChar.addCompositeGlyph(new PCLCharacterDefinition(compositeIndex,
                             PCLCharacterFormat.TrueType,
-                            PCLCharacterClass.TrueType, compositeData, pclByteWriter, true));
+                            PCLCharacterClass.TrueType, compositeData, true));
                 }
             }
 
index 35e37f23f9726518aaf18a66ad76201529fc1bbf..6839bf94857c003d493809e937d56f130fd5b175 100644 (file)
@@ -55,6 +55,8 @@ public class PCLTTFFontReader extends PCLFontReader {
     private PCLTTFOS2FontTable os2Table;
     private PCLTTFPOSTFontTable postTable;
     private PCLTTFTableFactory ttfTableFactory;
+    private Map<Integer, int[]> charOffsets;
+    private Map<Integer, Integer> charMtxOffsets;
 
     private static final int HMTX_RESTRICT_SIZE = 50000;
 
@@ -115,8 +117,8 @@ public class PCLTTFFontReader extends PCLFontReader {
     private int scaleFactor = -1;
     private PCLSymbolSet symbolSet = PCLSymbolSet.Bound_Generic;
 
-    public PCLTTFFontReader(Typeface font, PCLByteWriterUtil pclByteWriter) throws IOException {
-        super(font, pclByteWriter);
+    public PCLTTFFontReader(Typeface font) throws IOException {
+        super(font);
         loadFont();
     }
 
@@ -461,7 +463,7 @@ public class PCLTTFFontReader extends PCLFontReader {
             throws IOException {
         List<PCLFontSegment> fontSegments = new ArrayList<PCLFontSegment>();
         fontSegments.add(new PCLFontSegment(SegmentID.CC, getCharacterComplement()));
-        fontSegments.add(new PCLFontSegment(SegmentID.PA, pclByteWriter.toByteArray(os2Table.getPanose())));
+        fontSegments.add(new PCLFontSegment(SegmentID.PA, PCLByteWriterUtil.toByteArray(os2Table.getPanose())));
         fontSegments.add(new PCLFontSegment(SegmentID.GT, getGlobalTrueTypeData(mappedGlyphs)));
         fontSegments.add(new PCLFontSegment(SegmentID.CP, ttfFont.getCopyrightNotice().getBytes("US-ASCII")));
         fontSegments.add(new PCLFontSegment(SegmentID.NULL, new byte[0]));
@@ -484,8 +486,8 @@ public class PCLTTFFontReader extends PCLFontReader {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         List<TableOffset> tableOffsets = new ArrayList<TableOffset>();
         // Version
-        baos.write(pclByteWriter.unsignedInt(1)); // Major
-        baos.write(pclByteWriter.unsignedInt(0)); // Minor
+        baos.write(PCLByteWriterUtil.unsignedInt(1)); // Major
+        baos.write(PCLByteWriterUtil.unsignedInt(0)); // Minor
         int numTables = 5; // head, hhea, hmtx, maxp and gdir
         // Optional Hint Tables
         OFDirTabEntry headTable = ttfFont.getDirectoryEntry(OFTableName.CVT);
@@ -500,12 +502,12 @@ public class PCLTTFFontReader extends PCLFontReader {
         if (prepTable != null) {
             numTables++;
         }
-        baos.write(pclByteWriter.unsignedInt(numTables)); // numTables
-        int maxPowerNumTables = pclByteWriter.maxPower2(numTables);
+        baos.write(PCLByteWriterUtil.unsignedInt(numTables)); // numTables
+        int maxPowerNumTables = PCLByteWriterUtil.maxPower2(numTables);
         int searchRange = maxPowerNumTables * 16;
-        baos.write(pclByteWriter.unsignedInt(searchRange));
-        baos.write(pclByteWriter.unsignedInt(pclByteWriter.log(maxPowerNumTables, 2))); // Entry Selector
-        baos.write(pclByteWriter.unsignedInt(numTables * 16 - searchRange)); // Range shift
+        baos.write(PCLByteWriterUtil.unsignedInt(searchRange));
+        baos.write(PCLByteWriterUtil.unsignedInt(PCLByteWriterUtil.log(maxPowerNumTables, 2))); // Entry Selector
+        baos.write(PCLByteWriterUtil.unsignedInt(numTables * 16 - searchRange)); // Range shift
 
         // Add default data tables
         writeTrueTypeTable(baos, OFTableName.HEAD, tableOffsets);
@@ -555,20 +557,20 @@ public class PCLTTFFontReader extends PCLFontReader {
         OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table);
         if (tabEntry != null) {
             baos.write(tabEntry.getTag());
-            baos.write(pclByteWriter.unsignedLongInt(tabEntry.getChecksum()));
+            baos.write(PCLByteWriterUtil.unsignedLongInt(tabEntry.getChecksum()));
             TableOffset newTableOffset = new TableOffset(tabEntry.getOffset(),
                     tabEntry.getLength(), baos.size());
             tableOffsets.add(newTableOffset);
-            baos.write(pclByteWriter.unsignedLongInt(0)); // Offset to be set later
-            baos.write(pclByteWriter.unsignedLongInt(tabEntry.getLength()));
+            baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Offset to be set later
+            baos.write(PCLByteWriterUtil.unsignedLongInt(tabEntry.getLength()));
         }
     }
 
     private void writeGDIR(ByteArrayOutputStream baos) throws UnsupportedEncodingException, IOException {
         baos.write("gdir".getBytes("ISO-8859-1"));
-        baos.write(pclByteWriter.unsignedLongInt(0)); // Checksum
-        baos.write(pclByteWriter.unsignedLongInt(0)); // Offset
-        baos.write(pclByteWriter.unsignedLongInt(0)); // Length
+        baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Checksum
+        baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Offset
+        baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Length
     }
 
     private ByteArrayOutputStream copyTables(List<TableOffset> tableOffsets,
@@ -576,7 +578,7 @@ public class PCLTTFFontReader extends PCLFontReader {
             throws IOException {
         Map<Integer, byte[]> offsetValues = new HashMap<Integer, byte[]>();
         for (TableOffset tableOffset : tableOffsets) {
-            offsetValues.put(tableOffset.getNewOffset(), pclByteWriter.unsignedLongInt(baos.size()));
+            offsetValues.put(tableOffset.getNewOffset(), PCLByteWriterUtil.unsignedLongInt(baos.size()));
             if (tableOffset.getOriginOffset() == -1) { // Update the offset in the table directory
                 baos.write(hmtxTable);
             } else {
@@ -604,7 +606,7 @@ public class PCLTTFFontReader extends PCLFontReader {
             throws IOException {
         byte[] softFont = baos.toByteArray();
         for (int offset : offsets.keySet()) {
-            pclByteWriter.updateDataAtLocation(softFont, offsets.get(offset), offset);
+            PCLByteWriterUtil.updateDataAtLocation(softFont, offsets.get(offset), offset);
         }
         baos = new ByteArrayOutputStream();
         baos.write(softFont);
@@ -613,32 +615,34 @@ public class PCLTTFFontReader extends PCLFontReader {
 
     @Override
     public Map<Integer, int[]> getCharacterOffsets() throws IOException {
-        List<OFMtxEntry> mtx = ttfFont.getMtx();
-        OFTableName glyfTag = OFTableName.GLYF;
-        Map<Integer, int[]> charOffsets = new HashMap<Integer, int[]>();
-        OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(glyfTag);
-        if (ttfFont.seekTab(reader, glyfTag, 0)) {
-            for (int i = 1; i < mtx.size(); i++) {
-                OFMtxEntry entry = mtx.get(i);
-                OFMtxEntry nextEntry;
-                int nextOffset = 0;
-                int charCode = 0;
-                if (entry.getUnicodeIndex().size() > 0) {
-                    charCode = (Integer) entry.getUnicodeIndex().get(0);
-                } else {
-                    charCode = entry.getIndex();
+        if (charOffsets == null) {
+            List<OFMtxEntry> mtx = ttfFont.getMtx();
+            OFTableName glyfTag = OFTableName.GLYF;
+            charOffsets = new HashMap<Integer, int[]>();
+            OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(glyfTag);
+            if (ttfFont.seekTab(reader, glyfTag, 0)) {
+                for (int i = 1; i < mtx.size(); i++) {
+                    OFMtxEntry entry = mtx.get(i);
+                    OFMtxEntry nextEntry;
+                    int nextOffset = 0;
+                    int charCode = 0;
+                    if (entry.getUnicodeIndex().size() > 0) {
+                        charCode = (Integer) entry.getUnicodeIndex().get(0);
+                    } else {
+                        charCode = entry.getIndex();
+                    }
+
+                    if (i < mtx.size() - 1) {
+                        nextEntry = mtx.get(i + 1);
+                        nextOffset = (int) nextEntry.getOffset();
+                    } else {
+                        nextOffset = (int) ttfFont.getLastGlyfLocation();
+                    }
+                    int glyphOffset = (int) entry.getOffset();
+                    int glyphLength = nextOffset - glyphOffset;
+
+                    charOffsets.put(charCode, new int[]{(int) tabEntry.getOffset() + glyphOffset, glyphLength});
                 }
-
-                if (i < mtx.size() - 1) {
-                    nextEntry = mtx.get(i + 1);
-                    nextOffset = (int) nextEntry.getOffset();
-                } else {
-                    nextOffset = (int) ttfFont.getLastGlyfLocation();
-                }
-                int glyphOffset = (int) entry.getOffset();
-                int glyphLength = nextOffset - glyphOffset;
-
-                charOffsets.put(charCode, new int[]{(int) tabEntry.getOffset() + glyphOffset, glyphLength});
             }
         }
         return charOffsets;
@@ -660,11 +664,11 @@ public class PCLTTFFontReader extends PCLFontReader {
         if (tabEntry != null) {
             baos.write(tabEntry.getTag());
             // Override the original checksum for the subset version
-            baos.write(pclByteWriter.unsignedLongInt(getCheckSum(hmtxTable, 0, hmtxTable.length)));
+            baos.write(PCLByteWriterUtil.unsignedLongInt(getCheckSum(hmtxTable, 0, hmtxTable.length)));
             TableOffset newTableOffset = new TableOffset(-1, hmtxTable.length, baos.size());
             tableOffsets.add(newTableOffset);
-            baos.write(pclByteWriter.unsignedLongInt(0)); // Offset to be set later
-            baos.write(pclByteWriter.unsignedLongInt(hmtxTable.length));
+            baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Offset to be set later
+            baos.write(PCLByteWriterUtil.unsignedLongInt(hmtxTable.length));
         }
     }
 
@@ -728,5 +732,26 @@ public class PCLTTFFontReader extends PCLFontReader {
         out[offset] = b1;
         out[offset + 1] = b2;
     }
+
+    public Map<Integer, Integer> scanMtxCharacters() throws IOException {
+        if (charMtxOffsets == null) {
+            charMtxOffsets = new HashMap<Integer, Integer>();
+            List<OFMtxEntry> mtx = ttfFont.getMtx();
+            OFTableName glyfTag = OFTableName.GLYF;
+            if (ttfFont.seekTab(reader, glyfTag, 0)) {
+                for (int i = 1; i < mtx.size(); i++) {
+                    OFMtxEntry entry = mtx.get(i);
+                    int charCode = 0;
+                    if (entry.getUnicodeIndex().size() > 0) {
+                        charCode = (Integer) entry.getUnicodeIndex().get(0);
+                    } else {
+                        charCode = entry.getIndex();
+                    }
+                    charMtxOffsets.put(charCode, i);
+                }
+            }
+        }
+        return charMtxOffsets;
+    }
 }
 
index 65ac6ef0b657d7dbe531799c97344803fee46a87..fe637589db422873b5595051990f0b3c43a6a838 100644 (file)
@@ -20,9 +20,13 @@ package org.apache.fop.render.pcl;
 
 import java.awt.Color;
 import java.awt.Dimension;
+import java.awt.FontFormatException;
 import java.awt.Rectangle;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 
 import javax.xml.transform.stream.StreamResult;
 
@@ -30,8 +34,13 @@ import org.junit.Test;
 
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.FopFactory;
+import org.apache.fop.fonts.EmbeddingMode;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontType;
+import org.apache.fop.fonts.MultiByteFont;
 import org.apache.fop.render.intermediate.IFContext;
 import org.apache.fop.render.intermediate.IFException;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
 
 import junit.framework.Assert;
 
@@ -57,4 +66,35 @@ public class PCLPainterTestCase {
         Assert.assertTrue(output.toString().contains("*v255a0b0c0I\u001B*v0S\u001B*c0.01h0.01V\u001B*c0P"));
     }
 
+    @Test
+    public void testTruetype() throws IFException, IOException, FontFormatException, URISyntaxException {
+        String optimizeResources = getPCL(true).toString();
+        String notOptimizeResources = getPCL(false).toString();
+        Assert.assertTrue(notOptimizeResources.contains("DejaVu"));
+        Assert.assertFalse(optimizeResources.contains("DejaVu"));
+        Assert.assertEquals(optimizeResources.length(), 935);
+    }
+
+    private ByteArrayOutputStream getPCL(boolean optimizeResources)
+            throws IFException, URISyntaxException, IOException, FontFormatException {
+        Rectangle size = new Rectangle(1, 1);
+        PCLPageDefinition pclPageDef = new PCLPageDefinition("", 0, new Dimension(), size, true);
+        PCLDocumentHandler documentHandler = new PCLDocumentHandler(new IFContext(ua));
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        documentHandler.setResult(new StreamResult(output));
+        documentHandler.startDocument();
+        PCLPainter pclPainter = new PCLPainter(documentHandler, pclPageDef);
+        pclPainter.getPCLUtil().setOptimizeResources(optimizeResources);
+        FontInfo fi = new FontInfo();
+        fi.addFontProperties("", "", "", 0);
+        MultiByteFont mbf = new MultiByteFont(ua.getResourceResolver(), EmbeddingMode.AUTO);
+        mbf.setEmbedURI(new URI("test/resources/fonts/ttf/DejaVuLGCSerif.ttf"));
+        mbf.setFontType(FontType.TRUETYPE);
+        fi.addMetrics("", new CustomFontMetricsMapper(mbf));
+        documentHandler.setFontInfo(fi);
+        pclPainter.setFont("", "", 0, "", 0, Color.BLACK);
+        pclPainter.drawText(0, 0, 0, 0, null, "test");
+        return output;
+    }
+
 }
index a155dd43d2c175715aff8ffed720337c61d5018d..85e15b0a02b52ed6756eefcdeedd43aff706d9cb 100644 (file)
@@ -29,8 +29,8 @@ import org.apache.fop.render.pcl.fonts.truetype.PCLTTFFontReader;
 
 public class MockPCLTTFFontReader extends PCLTTFFontReader {
 
-    public MockPCLTTFFontReader(Typeface font, PCLByteWriterUtil pclByteWriter) throws IOException {
-        super(font, pclByteWriter);
+    public MockPCLTTFFontReader(Typeface font) throws IOException {
+        super(font);
     }
 
     @Override
index a21f204bfcf8bafbceddc72f2d23f8b44fee3c98..a558a23d90d30ed9b375fe901211edf3820b345c 100644 (file)
@@ -20,31 +20,24 @@ package org.apache.fop.render.pcl.fonts;
 
 import java.io.IOException;
 
-import org.junit.Before;
 import org.junit.Test;
 
 import static org.junit.Assert.assertArrayEquals;
 
 public class PCLByteWriterUtilTestCase {
-    private PCLByteWriterUtil byteWriter;
-
-    @Before
-    public void setUp() {
-        byteWriter = new PCLByteWriterUtil();
-    }
 
     @Test
     public void testWriteMethods() throws IOException {
-        byte[] output = byteWriter.writeCommand("(s4X");
+        byte[] output = PCLByteWriterUtil.writeCommand("(s4X");
         // 27 = PCL escape character with rest in ASCII format
         byte[] command = {27, 40, 115, 52, 88};
         assertArrayEquals(command, output);
 
-        byte[] resultB = byteWriter.unsignedLongInt(102494);
+        byte[] resultB = PCLByteWriterUtil.unsignedLongInt(102494);
         byte[] compareB = {0, 1, -112, 94};
         assertArrayEquals(compareB, resultB);
 
-        byte[] resultC = byteWriter.unsignedInt(1024);
+        byte[] resultC = PCLByteWriterUtil.unsignedInt(1024);
         byte[] compareC = {4, 0};
         assertArrayEquals(compareC, resultC);
     }
@@ -53,21 +46,21 @@ public class PCLByteWriterUtilTestCase {
     public void testUtilMethods() throws IOException {
         byte[] anArray = {1, 2, 3, 4, 5, 9, 10};
         byte[] insertArray = {6, 7, 8};
-        byte[] result = byteWriter.insertIntoArray(5, anArray, insertArray);
+        byte[] result = PCLByteWriterUtil.insertIntoArray(5, anArray, insertArray);
         byte[] compareA = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         assertArrayEquals(compareA, result);
 
         byte[] reverse = {10, 9, 8, 7, 6};
-        byteWriter.updateDataAtLocation(compareA, reverse, 5);
+        PCLByteWriterUtil.updateDataAtLocation(compareA, reverse, 5);
         byte[] compareB = {1, 2, 3, 4, 5, 10, 9, 8, 7, 6};
         assertArrayEquals(compareB, compareA);
 
         byte[] anArrayC = {1, 2, 3, 4, 5};
-        byte[] resultC = byteWriter.padBytes(anArrayC, 10);
+        byte[] resultC = PCLByteWriterUtil.padBytes(anArrayC, 10);
         byte[] compareC = {1, 2, 3, 4, 5, 0, 0, 0, 0, 0};
         assertArrayEquals(compareC, resultC);
 
-        byte[] resultD = byteWriter.padBytes(anArrayC, 10, 1);
+        byte[] resultD = PCLByteWriterUtil.padBytes(anArrayC, 10, 1);
         byte[] compareD = {1, 2, 3, 4, 5, 1, 1, 1, 1, 1};
         assertArrayEquals(compareD, resultD);
     }
index 2860afbdf0cd1c49a4810ce31f22ad70c3a938f8..cf05a0ca5843a26db96c7dd7c6d4e026ccdeb8a1 100644 (file)
@@ -46,7 +46,6 @@ public class PCLFontReaderFactoryTestCase {
         // Have to mock the input stream twice otherwise get a Stream is closed exception
         when(((CustomFont) customFont.getRealFont()).getInputStream()).thenReturn(
                 new FileInputStream(new File(TEST_FONT_TTF)));
-        PCLFontReaderFactory fontReaderFactory = PCLFontReaderFactory.getInstance(null);
-        assertTrue(fontReaderFactory.createInstance(customFont) instanceof PCLTTFFontReader);
+        assertTrue(PCLFontReaderFactory.createInstance(customFont) instanceof PCLTTFFontReader);
     }
 }
index 5673efbb47111e95a4a8eb11493d2f9cf7f2ae89..08323e0cfa776124e80a628b046160a147520cca 100644 (file)
@@ -27,7 +27,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.junit.Before;
 import org.junit.Test;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -44,14 +43,8 @@ import org.apache.fop.render.pcl.fonts.truetype.PCLTTFFontReader;
 public class PCLTTFFontReaderTestCase {
 
     private CustomFontMetricsMapper customFont = mock(CustomFontMetricsMapper.class);
-    private PCLByteWriterUtil byteWriter;
     private static final String TEST_FONT_A = "./test/resources/fonts/ttf/DejaVuLGCSerif.ttf";
 
-    @Before
-    public void setUp() {
-        byteWriter = new PCLByteWriterUtil();
-    }
-
     @Test
     public void verifyFontAData() throws Exception {
         CustomFont sbFont = mock(CustomFont.class);
@@ -62,7 +55,7 @@ public class PCLTTFFontReaderTestCase {
         when(font.getGIDFromChar('e')).thenReturn(101);
         when(font.getGIDFromChar('l')).thenReturn(108);
         when(font.getGIDFromChar('o')).thenReturn(111);
-        PCLTTFFontReader reader = new MockPCLTTFFontReader(customFont, byteWriter);
+        PCLTTFFontReader reader = new MockPCLTTFFontReader(customFont);
         reader.setFont(font);
         verifyFontData(reader);
         validateOffsets(reader);
index 04849db873ef4316320eb711b2f713d35b4eac28..4a8edb40190294ec5be7ff43f0289197d88017de 100644 (file)
@@ -46,6 +46,7 @@ public class PCLTTFCharacterWriterTestCase {
     public void verifyCharacterDefinition() throws Exception {
         CustomFont sbFont = mock(CustomFont.class);
         when(customFont.getRealFont()).thenReturn(sbFont);
+        when(sbFont.getInputStream()).thenReturn(new FileInputStream(TEST_FONT_A));
         softFont = new PCLSoftFont(1, customFont, false);
         TTFFile openFont = new TTFFile();
         FontFileReader reader = new FontFileReader(new FileInputStream(new File(TEST_FONT_A)));
@@ -53,15 +54,15 @@ public class PCLTTFCharacterWriterTestCase {
         openFont.readFont(reader, header);
         softFont.setOpenFont(openFont);
         softFont.setReader(reader);
+        softFont.setMtxCharIndexes(new PCLTTFFontReader(customFont).scanMtxCharacters());
 
         characterWriter = new PCLTTFCharacterWriter(softFont);
         byte[] charDefinition = characterWriter.writeCharacterDefinitions("f");
-        PCLByteWriterUtil pclByteWriter = new PCLByteWriterUtil();
         // Character command
-        byte[] command = pclByteWriter.writeCommand(String.format("*c%dE", 32));
+        byte[] command = PCLByteWriterUtil.writeCommand(String.format("*c%dE", 32));
         assertArrayEquals(getBytes(charDefinition, 0, 6), command);
         // Character definition command
-        byte[] charDefCommand = pclByteWriter.writeCommand(String.format("(s%dW", 210));
+        byte[] charDefCommand = PCLByteWriterUtil.writeCommand(String.format("(s%dW", 210));
         assertArrayEquals(getBytes(charDefinition, 6, 7), charDefCommand);
     }