From be0c18fc67b546056a8dc882ba760be41f690fe0 Mon Sep 17 00:00:00 2001 From: Simon Steiner Date: Mon, 15 Aug 2016 14:15:27 +0000 Subject: [PATCH] FOP-2642: Add optimize-resources for IF to PCL git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1756387 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/fop/fonts/CIDSubset.java | 3 +- .../fop/render/pcl/Java2DRendererOption.java | 1 + .../fop/render/pcl/PCLDocumentHandler.java | 60 ++++++- .../apache/fop/render/pcl/PCLGenerator.java | 24 ++- .../org/apache/fop/render/pcl/PCLPainter.java | 21 ++- .../fop/render/pcl/PCLRendererConfig.java | 7 + .../render/pcl/PCLRendererConfigurator.java | 3 + .../fop/render/pcl/PCLRenderingUtil.java | 9 ++ .../render/pcl/fonts/PCLByteWriterUtil.java | 33 ++-- .../pcl/fonts/PCLCharacterDefinition.java | 19 +-- .../render/pcl/fonts/PCLCharacterWriter.java | 2 - .../fop/render/pcl/fonts/PCLFontReader.java | 5 +- .../pcl/fonts/PCLFontReaderFactory.java | 15 +- .../render/pcl/fonts/PCLSoftFontManager.java | 147 ++++++++++-------- .../fonts/truetype/PCLTTFCharacterWriter.java | 24 +-- .../pcl/fonts/truetype/PCLTTFFontReader.java | 117 ++++++++------ .../fop/render/pcl/PCLPainterTestCase.java | 40 +++++ .../pcl/fonts/MockPCLTTFFontReader.java | 4 +- .../pcl/fonts/PCLByteWriterUtilTestCase.java | 21 +-- .../fonts/PCLFontReaderFactoryTestCase.java | 3 +- .../pcl/fonts/PCLTTFFontReaderTestCase.java | 9 +- .../PCLTTFCharacterWriterTestCase.java | 7 +- 22 files changed, 362 insertions(+), 212 deletions(-) diff --git a/fop-core/src/main/java/org/apache/fop/fonts/CIDSubset.java b/fop-core/src/main/java/org/apache/fop/fonts/CIDSubset.java index 01b8495f8..e0fbdd6c2 100644 --- a/fop-core/src/main/java/org/apache/fop/fonts/CIDSubset.java +++ b/fop-core/src/main/java/org/apache/fop/fonts/CIDSubset.java @@ -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 usedGlyphs = new HashMap(); + private Map usedGlyphs = new LinkedHashMap(); /** * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index) diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/Java2DRendererOption.java b/fop-core/src/main/java/org/apache/fop/render/pcl/Java2DRendererOption.java index 9ec0b779b..7a0a4a77e 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/Java2DRendererOption.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/Java2DRendererOption.java @@ -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; diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLDocumentHandler.java b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLDocumentHandler.java index 66655a721..a4492b175 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLDocumentHandler.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLDocumentHandler.java @@ -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> fontManagerMapEntry : gen.fontManagerMap.entrySet()) { + PCLSoftFontManager softFontManager = fontManagerMapEntry.getKey(); + for (Map.Entry 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 diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLGenerator.java b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLGenerator.java index 589779ad9..6a4f3215e 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLGenerator.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLGenerator.java @@ -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 fontReaderMap = new HashMap(); + protected Map> fontManagerMap + = new LinkedHashMap>(); 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()); + } + Map 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; diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLPainter.java b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLPainter.java index 65e996d08..60d6eb89f 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLPainter.java @@ -85,8 +85,7 @@ public class PCLPainter extends AbstractIFPainter implements private Stack graphicContextStack = new Stack(); private GraphicContext graphicContext = new GraphicContext(); - - private PCLSoftFontManager sfManager = new PCLSoftFontManager(); + private PCLSoftFontManager sfManager; /** * Main constructor. @@ -338,12 +337,20 @@ public class PCLPainter extends AbstractIFPainter 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); diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfig.java b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfig.java index 30429a7c5..06aebba71 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfig.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfig.java @@ -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 getParam(Java2DRendererOption option, Class 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)); } } diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java index 7a92b7408..1641055dd 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java @@ -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 diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRenderingUtil.java b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRenderingUtil.java index 674605bde..0c4fb522f 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRenderingUtil.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/PCLRenderingUtil.java @@ -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; + } + } diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java index 1b9382f7b..3a5d68602 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java @@ -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")); diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java index c275084dc..3c4053c72 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java @@ -31,18 +31,15 @@ public class PCLCharacterDefinition { private boolean hasContinuation; private PCLCharacterFormat charFormat; private PCLCharacterClass charClass; - private PCLByteWriterUtil pclByteWriter; private List 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) { diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java index df04371e0..51e067980 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java @@ -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; diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java index 6bd5192ac..b0b95f34b 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java @@ -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 scanMtxCharacters() throws IOException; /** Segmented Font Data **/ public abstract List getFontSegments(Map mappedGlyphs) diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java index 15c4e8d54..aced97a99 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java @@ -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(); diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java index 621ea4f18..42616581e 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java @@ -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 fontReaderMap; private PCLFontReader fontReader; - private PCLByteWriterUtil pclByteWriter = new PCLByteWriterUtil(); private List fonts = new ArrayList(); - private PCLFontReaderFactory fontReaderFactory; private static final int SOFT_FONT_SIZE = 255; - public ByteArrayOutputStream makeSoftFont(Typeface font) throws IOException { + public PCLSoftFontManager(Map fontReaderMap) { + this.fontReaderMap = fontReaderMap; + } + + public ByteArrayOutputStream makeSoftFont(Typeface font, String text) throws IOException { List> 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()); } if (fontReader != null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PCLSoftFont softFont = null; for (Map 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> mappedGlyphs, + PCLSoftFont last) { + if (text == null) { + Iterator 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> mapFontGlyphs(Typeface tf) { List> mappedGlyphs = new ArrayList>(); 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 mappedGlyphs) throws IOException { + private void writeFontHeader(Map 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()); } diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java index 41fefaaf0..d09048bc0 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java @@ -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 scanMtxCharacters() throws IOException { - Map charMtxOffsets = new HashMap(); - List 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)); } } diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java index 35e37f23f..6839bf948 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java @@ -55,6 +55,8 @@ public class PCLTTFFontReader extends PCLFontReader { private PCLTTFOS2FontTable os2Table; private PCLTTFPOSTFontTable postTable; private PCLTTFTableFactory ttfTableFactory; + private Map charOffsets; + private Map 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 fontSegments = new ArrayList(); 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 tableOffsets = new ArrayList(); // 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 tableOffsets, @@ -576,7 +578,7 @@ public class PCLTTFFontReader extends PCLFontReader { throws IOException { Map offsetValues = new HashMap(); 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 getCharacterOffsets() throws IOException { - List mtx = ttfFont.getMtx(); - OFTableName glyfTag = OFTableName.GLYF; - Map charOffsets = new HashMap(); - 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 mtx = ttfFont.getMtx(); + OFTableName glyfTag = OFTableName.GLYF; + charOffsets = new HashMap(); + 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 scanMtxCharacters() throws IOException { + if (charMtxOffsets == null) { + charMtxOffsets = new HashMap(); + List 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; + } } diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/PCLPainterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pcl/PCLPainterTestCase.java index 65ac6ef0b..fe637589d 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pcl/PCLPainterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/PCLPainterTestCase.java @@ -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; + } + } diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/MockPCLTTFFontReader.java b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/MockPCLTTFFontReader.java index a155dd43d..85e15b0a0 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/MockPCLTTFFontReader.java +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/MockPCLTTFFontReader.java @@ -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 diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtilTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtilTestCase.java index a21f204bf..a558a23d9 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtilTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtilTestCase.java @@ -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); } diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactoryTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactoryTestCase.java index 2860afbdf..cf05a0ca5 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactoryTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactoryTestCase.java @@ -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); } } diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLTTFFontReaderTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLTTFFontReaderTestCase.java index 5673efbb4..08323e0cf 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLTTFFontReaderTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLTTFFontReaderTestCase.java @@ -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); diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriterTestCase.java index 04849db87..4a8edb401 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriterTestCase.java @@ -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); } -- 2.39.5