diff options
author | Jeremias Maerki <jeremias@apache.org> | 2003-03-11 13:05:43 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2003-03-11 13:05:43 +0000 |
commit | 1e5d512c216d329effa693b91ef64652945def6a (patch) | |
tree | 5bd3521ee8121eade7bf1909ceaf29cfc0263fd1 /src/java/org/apache/fop/render/ps | |
parent | 73c824d39411bf11ad0c2f4e1c57cd9c484665f9 (diff) | |
download | xmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.tar.gz xmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.zip |
Moved sources from src/org/** to src/java/org/**
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196061 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/render/ps')
-rw-r--r-- | src/java/org/apache/fop/render/ps/ASCII85OutputStream.java | 254 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java | 134 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/DSCConstants.java | 202 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/Finalizable.java | 74 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java | 85 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSGenerator.java | 371 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSGraphics2D.java | 1134 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSProcSets.java | 200 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSRenderer.java | 901 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSState.java | 97 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSTextElementBridge.java | 159 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSTextPainter.java | 435 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSXMLHandler.java | 379 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java | 217 |
14 files changed, 4642 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/render/ps/ASCII85OutputStream.java b/src/java/org/apache/fop/render/ps/ASCII85OutputStream.java new file mode 100644 index 000000000..7a0c2aeef --- /dev/null +++ b/src/java/org/apache/fop/render/ps/ASCII85OutputStream.java @@ -0,0 +1,254 @@ +/* + * $Id: ASCII85OutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; + +/** + * This class applies a ASCII85 encoding to the stream. + * + * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a> + * @version $Id: ASCII85OutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + */ +public class ASCII85OutputStream extends FilterOutputStream + implements Finalizable { + + private static final int ZERO = 0x7A; //"z" + private static final byte[] ZERO_ARRAY = {(byte)ZERO}; + private static final int START = 0x21; //"!" + private static final int EOL = 0x0A; //"\n" + private static final byte[] EOD = {0x7E, 0x3E}; //"~>" + + private static final long BASE85_4 = 85; + private static final long BASE85_3 = BASE85_4 * BASE85_4; + private static final long BASE85_2 = BASE85_3 * BASE85_4; + private static final long BASE85_1 = BASE85_2 * BASE85_4; + + private static final boolean DEBUG = false; + + private int pos = 0; + private long buffer = 0; + private int posinline = 0; + private int bw = 0; + + + /** @see java.io.FilterOutputStream **/ + public ASCII85OutputStream(OutputStream out) { + super(out); + } + + + /** @see java.io.FilterOutputStream **/ + public void write(int b) throws IOException { + if (pos == 0) { + buffer += (b << 24) & 0xff000000L; + } else if (pos == 1) { + buffer += (b << 16) & 0xff0000L; + } else if (pos == 2) { + buffer += (b << 8) & 0xff00L; + } else { + buffer += b & 0xffL; + } + pos++; + + if (pos > 3) { + checkedWrite(convertWord(buffer)); + buffer = 0; + pos = 0; + } + } + + + private void checkedWrite(int b) throws IOException { + if (posinline == 80) { + out.write(EOL); bw++; + posinline = 0; + } + checkedWrite(b); + posinline++; + bw++; + } + + + private void checkedWrite(byte[] buf) throws IOException { + checkedWrite(buf, buf.length); + } + + + private void checkedWrite(byte[] buf , int len) throws IOException { + if (posinline + len > 80) { + int firstpart = len - (posinline + len - 80); + if (firstpart > 0) { + out.write(buf, 0, firstpart); + } + out.write(EOL); bw++; + int rest = len - firstpart; + if (rest > 0) { + out.write(buf, firstpart, rest); + } + posinline = rest; + } else { + out.write(buf, 0, len); + posinline += len; + } + bw += len; + } + + + /** + * This converts a 32 bit value (4 bytes) into 5 bytes using base 85. + * each byte in the result starts with zero at the '!' character so + * the resulting base85 number fits into printable ascii chars + * + * @param word the 32 bit unsigned (hence the long datatype) word + * @return 5 bytes (or a single byte of the 'z' character for word + * values of 0) + */ + private byte[] convertWord(long word) { + word = word & 0xffffffff; + + if (word == 0) { + return ZERO_ARRAY; + } else { + if (word < 0) { + word = -word; + } + byte c1 = (byte)((word / BASE85_1) & 0xFF); + byte c2 = (byte)(((word - (c1 * BASE85_1)) / BASE85_2) & 0xFF); + byte c3 = + (byte)(((word - (c1 * BASE85_1) - (c2 * BASE85_2)) + / BASE85_3) & 0xFF); + byte c4 = + (byte)(((word - (c1 * BASE85_1) - (c2 * BASE85_2) - (c3 * BASE85_3)) + / BASE85_4) & 0xFF); + byte c5 = + (byte)(((word - (c1 * BASE85_1) - (c2 * BASE85_2) - (c3 * BASE85_3) + - (c4 * BASE85_4))) + & 0xFF); + + byte[] ret = { + (byte)(c1 + START), (byte)(c2 + START), + (byte)(c3 + START), (byte)(c4 + START), + (byte)(c5 + START) + }; + + if (DEBUG) { + for (int i = 0; i < ret.length; i++) { + if (ret[i] < 33 || ret[i] > 117) { + System.out.println("Illegal char value " + + new Integer(ret[i])); + } + } + } + return ret; + } + } + + + /** @see org.apache.fop.render.ps.Finalizable **/ + public void finalizeStream() throws IOException { + // now take care of the trailing few bytes. + // with n leftover bytes, we append 0 bytes to make a full group of 4 + // then convert like normal (except not applying the special zero rule) + // and write out the first n+1 bytes from the result + if (pos > 0) { + int rest = pos; + /* + byte[] lastdata = new byte[4]; + int i = 0; + for (int j = 0; j < 4; j++) { + if (j < rest) { + lastdata[j] = data[i++]; + } else { + lastdata[j] = 0; + } + } + + long val = ((lastdata[0] << 24) & 0xff000000L) + + ((lastdata[1] << 16) & 0xff0000L) + + ((lastdata[2] << 8) & 0xff00L) + + (lastdata[3] & 0xffL); + */ + + byte[] conv; + // special rule for handling zeros at the end + if (buffer != 0) { + conv = convertWord(buffer); + } else { + conv = new byte[5]; + for (int j = 0; j < 5; j++) { + conv[j] = (byte)'!'; + } + } + // assert rest+1 <= 5 + checkedWrite(conv, rest + 1); + } + // finally write the two character end of data marker + checkedWrite(EOD); + + flush(); + if (out instanceof Finalizable) { + ((Finalizable)out).finalizeStream(); + } + } + + + /** @see java.io.FilterOutputStream **/ + public void close() throws IOException { + finalizeStream(); + super.close(); + } + +} + + diff --git a/src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java b/src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java new file mode 100644 index 000000000..1be3766b0 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java @@ -0,0 +1,134 @@ +/* + * $Id: ASCIIHexOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; + +/** + * This class applies a ASCII Hex encoding to the stream. + * + * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a> + * @version $Id: ASCIIHexOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + */ +public class ASCIIHexOutputStream extends FilterOutputStream + implements Finalizable { + + private static final int EOL = 0x0A; //"\n" + private static final int EOD = 0x3E; //">" + private static final int ZERO = 0x30; //"0" + private static final int NINE = 0x39; //"9" + private static final int A = 0x41; //"A" + private static final int ADIFF = A - NINE - 1; + + private int posinline = 0; + + + /** @see java.io.FilterOutputStream **/ + public ASCIIHexOutputStream(OutputStream out) { + super(out); + } + + + /** @see java.io.FilterOutputStream **/ + public void write(int b) throws IOException { + b &= 0xFF; + + int digit1 = ((b & 0xF0) >> 4) + ZERO; + if (digit1 > NINE) { + digit1 += ADIFF; + } + out.write(digit1); + + int digit2 = (b & 0x0F) + ZERO; + if (digit2 > NINE) { + digit2 += ADIFF; + } + out.write(digit2); + + posinline++; + checkLineWrap(); + } + + + private void checkLineWrap() throws IOException { + //Maximum line length is 80 characters + if (posinline >= 40) { + out.write(EOL); + posinline = 0; + } + } + + + /** @see org.apache.fop.render.ps.Finalizable **/ + public void finalizeStream() throws IOException { + checkLineWrap(); + //Write closing character ">" + super.write(EOD); + + flush(); + if (out instanceof Finalizable) { + ((Finalizable) out).finalizeStream(); + } + } + + + /** @see java.io.FilterOutputStream **/ + public void close() throws IOException { + finalizeStream(); + super.close(); + } + + +} + + diff --git a/src/java/org/apache/fop/render/ps/DSCConstants.java b/src/java/org/apache/fop/render/ps/DSCConstants.java new file mode 100644 index 000000000..fcaee2ac9 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/DSCConstants.java @@ -0,0 +1,202 @@ +/* + * $Id: DSCConstants.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +/** + * This class defines constants with Strings for the DSC specification. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> + * @version $Id: DSCConstants.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + */ +public class DSCConstants { + + // ----==== General Header Comments ====---- + + /** Lead-in for a DSC-conformant PostScript file */ + public static final String PS_ADOBE_30 = "%!PS-Adobe-3.0"; + + /** Bounding box for the document */ + public static final String BBOX = "BoundingBox"; + /** Copyright information associated with the document or resource */ + public static final String COPYRIGHT = "Copyright"; + /** Creator of the document */ + public static final String CREATOR = "Creator"; + /** Date and time when the document was created */ + public static final String CREATION_DATE = "CreationDate"; + /** Type of data */ + public static final String DOCUMENT_DATA = "BoundingBox"; + /** Use for inidicating an emulator being invoked in the document */ + public static final String EMULATION = "Emulation"; + /** Explicit end of comments */ + public static final String END_COMMENTS = "EndComments"; + /** Required PostScript Level 1 extension for this document */ + public static final String EXTENSIONS = "Extensions"; + /** Indicates who is this document printed for */ + public static final String FOR = "For"; + /** Indicates the PostScript language level used in the document */ + public static final String LANGUAGE_LEVEL = "LanguageLevel"; + /** Indicates the orientation of the document */ + public static final String ORIENTATION = "Orientation"; + /** Number of pages in the document */ + public static final String PAGES = "Pages"; + /** Indicates the order of the pages */ + public static final String PAGE_ORDER = "PageOrder"; + /** Indicates how the document should be routed back to its owner */ + public static final String ROUTING = "Routing"; + /** Title of the document */ + public static final String TITLE = "Title"; + /** Version of the document */ + public static final String VERSION = "Version"; + + // ----==== General Body Comments ====---- + + /** Indicates a continued line */ + public static final String NEXT_LINE = "+ "; + + //Skipping BeginBinary/EndBinary. They are deprecated. + + /** Indicates the start of a data section*/ + public static final String BEGIN_DATA = "BeginData"; + /** Indicates the end of a data section*/ + public static final String END_DATA = "EndData"; + + /** Indicates the start of the defaults section */ + public static final String BEGIN_DEFAULTS = "BeginDefaults"; + /** Indicates the end of the defaults section */ + public static final String END_DEFAULTS = "EndDefaults"; + + /** Indicates the start of a non-PostScript section */ + public static final String BEGIN_EMULATION = "BeginEmulation"; + /** Indicates the end of a non-PostScript section */ + public static final String END_EMULATION = "EndEmulation"; + + /** Indicates the start of a preview section (EPS only)*/ + public static final String BEGIN_PREVIEW = "BeginPreview"; + /** Indicates the end of a preview section (EPS only)*/ + public static final String END_PREVIEW = "EndPreview"; + + /** Indicates the start of the prolog */ + public static final String BEGIN_PROLOG = "BeginProlog"; + /** Indicates the end of the prolog */ + public static final String END_PROLOG = "EndProlog"; + + /** Indicates the start of the document setup */ + public static final String BEGIN_SETUP = "BeginSetup"; + /** Indicates the end of the document setup */ + public static final String END_SETUP = "EndSetup"; + + + // ----==== General Page Comments ====---- + + /** Indicates the start of a graphic object */ + public static final String BEGIN_OBJECT = "BeginObject"; + /** Indicates the end of a graphic object */ + public static final String END_OBJECT = "EndObject"; + + /** Indicates the start of the page setup section */ + public static final String BEGIN_PAGE_SETUP = "BeginPageSetup"; + /** Indicates the end of the page setup section */ + public static final String END_PAGE_SETUP = "EndPageSetup"; + + /** Indicates a page number */ + public static final String PAGE = "Page"; + /** Bounding box for a page */ + public static final String PAGE_BBOX = "PageBoundingBox"; + /** Bounding box for a page */ + public static final String PAGE_ORIENTATION = "PageOrientation"; + + + // ----==== General Trailer Comments ====---- + + /** Indicates the start of the page trailer */ + public static final String PAGE_TRAILER = "PageTrailer"; + /** Indicates the start of the document trailer */ + public static final String TRAILER = "Trailer"; + /** Indicates the end of a page (NON-STANDARD!) */ + public static final String END_PAGE = "EndPage"; + /** Indicates the end of the document */ + public static final String EOF = "EOF"; + + + // ----==== Requirements Conventions ====---- + + /**@todo Add the missing comments */ + + // ----==== Requirement Body Comments ====---- + + /** Indicates the start of an embedded document */ + public static final String BEGIN_DOCUMENT = "BeginDocument"; + /** Indicates the end of an embedded document */ + public static final String END_DOCUMENT = "EndDocument"; + /** Indicates a referenced embedded document */ + public static final String INCLUDE_DOCUMENT = "IncludeDocument"; + + /** Indicates the start of a PPD feature */ + public static final String BEGIN_FEATURE = "BeginFeature"; + /** Indicates the end of a PPD feature */ + public static final String END_FEATURE = "EndFeature"; + /** Indicates a referenced a PPD feature */ + public static final String INCLUDE_FEATURE = "IncludeFeature"; + + //Skipping BeginFile/EndFile/IncludeFile. They are deprecated. + //Skipping BeginFont/EndFont/IncludeFont. They are deprecated. + //Skipping BeginProcSet/EndProcSet/IncludeProcSet. They are deprecated. + + /** Indicates the start of a resource (font, file, procset) */ + public static final String BEGIN_RESOURCE = "BeginResource"; + /** Indicates the end of a resource (font, file, procset) */ + public static final String END_RESOURCE = "EndResource"; + /** Indicates a referenced a resource (font, file, procset) */ + public static final String INCLUDE_RESOURCE = "IncludeResource"; + + +} diff --git a/src/java/org/apache/fop/render/ps/Finalizable.java b/src/java/org/apache/fop/render/ps/Finalizable.java new file mode 100644 index 000000000..af07bdfd6 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/Finalizable.java @@ -0,0 +1,74 @@ +/* + * $Id: Finalizable.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +/** + * This interface is used for special FilteredOutputStream classes that won't + * be closed (since this causes the target OutputStream to be closed, too) but + * where flush() is not enough, for example because a final marker has to be + * written to the target stream. + * + * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a> + * @version $Id: Finalizable.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + */ +public interface Finalizable { + + /** + * This method can be called instead of close() on a subclass of + * FilteredOutputStream when a final marker has to be written to the target + * stream, but close() cannot be called. + * + * @exception java.io.IOException In case of an IO problem + */ + void finalizeStream() + throws java.io.IOException; + +} diff --git a/src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java b/src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java new file mode 100644 index 000000000..3ebb7726c --- /dev/null +++ b/src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java @@ -0,0 +1,85 @@ +/* + * $Id: FlateEncodeOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.IOException; + +/** + * This class applies a FlateEncode filter to the stream. It is basically the + * normal DeflaterOutputStream except now also implementing the Finalizable + * interface. + * + * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a> + * @version $Id: FlateEncodeOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $ + */ +public class FlateEncodeOutputStream extends java.util.zip.DeflaterOutputStream + implements Finalizable { + + + /** @see java.util.zip.DeflaterOutputStream **/ + public FlateEncodeOutputStream(OutputStream out) { + super(out); + } + + + /** @see org.apache.fop.render.ps.Finalizable **/ + public void finalizeStream() throws IOException { + finish(); + flush(); + if (out instanceof Finalizable) { + ((Finalizable)out).finalizeStream(); + } + } + +} + + diff --git a/src/java/org/apache/fop/render/ps/PSGenerator.java b/src/java/org/apache/fop/render/ps/PSGenerator.java new file mode 100644 index 000000000..2b0622d96 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSGenerator.java @@ -0,0 +1,371 @@ +/* + * $Id: PSGenerator.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.OutputStream; +import java.io.IOException; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.Stack; + +/** + * This class is used to output PostScript code to an OutputStream. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> + * @version $Id: PSGenerator.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $ + */ +public class PSGenerator { + + /** + * Indicator for the PostScript interpreter that the value is provided + * later in the document (mostly in the %%Trailer section). + */ + public static final AtendIndicator ATEND = new AtendIndicator() {}; + + private OutputStream out; + + private Stack graphicsStateStack = new Stack(); + private PSState currentState; + + private StringBuffer tempBuffer = new StringBuffer(256); + + /** @see java.io.FilterOutputStream **/ + public PSGenerator(OutputStream out) { + this.out = out; + this.currentState = new PSState(); + this.graphicsStateStack.push(this.currentState); + } + + /** + * Writes a newline character to the OutputStream. + * + * @throws IOException In case of an I/O problem + */ + public final void newLine() throws IOException { + out.write('\n'); + } + + /** + * Formats a double value for PostScript output. + * + * @param value value to format + * @return the formatted value + */ + public String formatDouble(double value) { + NumberFormat nf = new java.text.DecimalFormat("0.#"); + return nf.format(value); + } + + /** + * Writes a PostScript command to the stream. + * + * @param cmd The PostScript code to be written. + * @exception IOException In case of an I/O problem + */ + public void write(String cmd) throws IOException { + if (cmd.length() > 255) { + throw new RuntimeException("PostScript command exceeded limit of 255 characters"); + } + out.write(cmd.getBytes("US-ASCII")); + } + + /** + * Writes a PostScript command to the stream and ends the line. + * + * @param cmd The PostScript code to be written. + * @exception IOException In case of an I/O problem + */ + public void writeln(String cmd) throws IOException { + write(cmd); + newLine(); + } + + /** + * Writes encoded data to the PostScript stream. + * + * @param cmd The encoded PostScript code to be written. + * @exception IOException In case of an I/O problem + */ + public void writeByteArr(byte[] cmd) throws IOException { + out.write(cmd); + newLine(); + } + + + /** + * Flushes the OutputStream. + * + * @exception IOException In case of an I/O problem + */ + public void flush() throws IOException { + out.flush(); + } + + + /** + * Escapes a character conforming to the rules established in the PostScript + * Language Reference (Search for "Literal Text Strings"). + * @param c character to escape + * @param target target StringBuffer to write the escaped character to + */ + public static final void escapeChar(char c, StringBuffer target) { + if (c > 127) { + target.append("\\"); + target.append(Integer.toOctalString(c)); + } else { + switch (c) { + case '\n': + target.append("\\n"); + break; + case '\r': + target.append("\\r"); + break; + case '\t': + target.append("\\t"); + break; + case '\b': + target.append("\\b"); + break; + case '\f': + target.append("\\f"); + break; + case '\\': + target.append("\\\\"); + break; + case '(': + target.append("\\("); + break; + case ')': + target.append("\\)"); + break; + default: + target.append(c); + } + } + } + + + /** + * Converts text by applying escaping rules established in the DSC specs. + * @param text Text to convert + * @return String The resulting String + */ + public static final String convertStringToDSC(String text) { + return convertStringToDSC(text, false); + } + + + /** + * Converts text by applying escaping rules established in the DSC specs. + * @param text Text to convert + * @param forceParentheses Force the use of parentheses + * @return String The resulting String + */ + public static final String convertStringToDSC(String text, + boolean forceParentheses) { + if ((text == null) || (text.length() == 0)) { + return "()"; + } else { + int initialSize = text.length(); + initialSize += initialSize / 2; + StringBuffer sb = new StringBuffer(initialSize); + if ((Long.getLong(text) != null) + || (text.indexOf(" ") >= 0) + || forceParentheses) { + + sb.append("("); + for (int i = 0; i < text.length(); i++) { + final char c = text.charAt(i); + escapeChar(c, sb); + } + sb.append(")"); + return sb.toString(); + } else { + return text; + } + } + } + + + /** + * Writes a DSC comment to the output stream. + * @param name Name of the DSC comment + * @exception IOException In case of an I/O problem + * @see org.apache.fop.render.ps.DSCConstants + */ + public void writeDSCComment(String name) throws IOException { + writeln("%%" + name); + } + + + /** + * Writes a DSC comment to the output stream. The parameter to the DSC + * comment can be any object. The object is converted to a String as + * necessary. + * @param name Name of the DSC comment + * @param param Single parameter to the DSC comment + * @exception IOException In case of an I/O problem + * @see org.apache.fop.render.ps.DSCConstants + */ + public void writeDSCComment(String name, Object param) throws IOException { + writeDSCComment(name, new Object[] {param}); + } + + + /** + * Writes a DSC comment to the output stream. The parameters to the DSC + * comment can be any object. The objects are converted to Strings as + * necessary. Please see the source code to find out what parameters are + * currently supported. + * @param name Name of the DSC comment + * @param params Array of parameters to the DSC comment + * @exception IOException In case of an I/O problem + * @see org.apache.fop.render.ps.DSCConstants + */ + public void writeDSCComment(String name, Object[] params) throws IOException { + tempBuffer.setLength(0); + tempBuffer.append("%%"); + tempBuffer.append(name); + if ((params != null) && (params.length > 0)) { + tempBuffer.append(": "); + for (int i = 0; i < params.length; i++) { + if (i > 0) { + tempBuffer.append(" "); + } + + if (params[i] instanceof String) { + tempBuffer.append(convertStringToDSC((String)params[i])); + } else if (params[i] instanceof AtendIndicator) { + tempBuffer.append("(atend)"); + } else if (params[i] instanceof Number) { + tempBuffer.append(params[i].toString()); + } else if (params[i] instanceof Date) { + DateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + tempBuffer.append(convertStringToDSC(df.format((Date)params[i]))); + } else { + throw new IllegalArgumentException("Unsupported parameter type: " + + params[i].getClass().getName()); + } + } + } + writeln(tempBuffer.toString()); + } + + + /** + * Saves the graphics state of the rendering engine. + * @exception IOException In case of an I/O problem + */ + public void saveGraphicsState() throws IOException { + writeln("gsave"); + + PSState state = (PSState)this.currentState.clone(); + this.graphicsStateStack.push(this.currentState); + this.currentState = state; + } + + /** + * Restores the last graphics state of the rendering engine. + * @exception IOException In case of an I/O problem + */ + public void restoreGraphicsState() throws IOException { + writeln("grestore"); + this.currentState = (PSState)this.graphicsStateStack.pop(); + } + + /** + * Concats the transformation matrix. + * @param a A part + * @param b B part + * @param c C part + * @param d D part + * @param e E part + * @param f F part + * @exception IOException In case of an I/O problem + */ + public void concatMatrix(double a, double b, + double c, double d, + double e, double f) throws IOException { + writeln("[" + formatDouble(a) + " " + + formatDouble(b) + " " + + formatDouble(c) + " " + + formatDouble(d) + " " + + formatDouble(e) + " " + + formatDouble(f) + "] concat"); + } + + /** + * Concats the transformations matrix. + * @param matrix Matrix to use + * @exception IOException In case of an I/O problem + */ + public void concatMatrix(double[] matrix) throws IOException { + concatMatrix(matrix[0], matrix[1], + matrix[2], matrix[3], + matrix[4], matrix[5]); + } + + /** + * Returns the current graphics state. + * @return the current graphics state + */ + public PSState getCurrentState() { + return this.currentState; + } + + + /** Used for the ATEND constant. See there. */ + private static interface AtendIndicator { + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java new file mode 100644 index 000000000..9a2908422 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java @@ -0,0 +1,1134 @@ +/* + * $Id: PSGraphics2D.java,v 1.11 2003/03/11 08:42:24 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +//Java +import java.util.List; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.io.IOException; + +// FOP +import org.apache.fop.layout.FontInfo; +import org.apache.fop.layout.FontState; + +// Batik +import org.apache.batik.ext.awt.g2d.AbstractGraphics2D; +import org.apache.batik.ext.awt.g2d.GraphicContext; + + +/** + * This concrete implementation of <tt>AbstractGraphics2D</tt> is a + * simple help to programmers to get started with their own + * implementation of <tt>Graphics2D</tt>. + * <tt>DefaultGraphics2D</tt> implements all the abstract methods + * is <tt>AbstractGraphics2D</tt> and makes it easy to start + * implementing a <tt>Graphic2D</tt> piece-meal. + * + * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> + * @version $Id: PSGraphics2D.java,v 1.11 2003/03/11 08:42:24 jeremias Exp $ + * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D + */ +public class PSGraphics2D extends AbstractGraphics2D { + + private boolean standalone = false; + + /** + * the PostScript genertaor being created + */ + protected PSGenerator gen; + + /** Currently valid FontState */ + protected FontState fontState; + + /** Overriding FontState */ + protected FontState overrideFontState = null; + + /** + * the current (internal) font name + */ + protected String currentFontName; + + /** + * the current font size in millipoints + */ + protected int currentFontSize; + + /** + * the current vertical position in millipoints from bottom + */ + protected int currentYPosition = 0; + + /** + * the current horizontal position in millipoints from left + */ + protected int currentXPosition = 0; + + /** + * the current colour for use in svg + */ + protected Color currentColour = new Color(0, 0, 0); + + /** FontInfo containing all available fonts */ + protected FontInfo fontInfo; + + /** + * Create a new Graphics2D that generates PostScript code. + * @param textAsShapes True if text should be rendered as graphics + * @param gen PostScript generator to use for output + * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean) + */ + public PSGraphics2D(boolean textAsShapes, PSGenerator gen) { + super(textAsShapes); + this.gen = gen; + } + + /** + * Constructor for creating copies + * @param g parent PostScript Graphics2D + */ + public PSGraphics2D(PSGraphics2D g) { + super(g); + } + + /** + * Sets the GraphicContext + * @param c GraphicContext to use + */ + public void setGraphicContext(GraphicContext c) { + gc = c; + } + + /** + * Creates a new <code>Graphics</code> object that is + * a copy of this <code>Graphics</code> object. + * @return a new graphics context that is a copy of + * this graphics context. + */ + public Graphics create() { + return new PSGraphics2D(this); + } + + /** + * Central handler for IOExceptions for this class. + * @param ioe IOException to handle + */ + protected void handleIOException(IOException ioe) { + ioe.printStackTrace(); + } + + /** + * Draws as much of the specified image as is currently available. + * The image is drawn with its top-left corner at + * (<i>x</i>, <i>y</i>) in this graphics context's coordinate + * space. Transparent pixels in the image do not affect whatever + * pixels are already there. + * <p> + * This method returns immediately in all cases, even if the + * complete image has not yet been loaded, and it has not been dithered + * and converted for the current output device. + * <p> + * If the image has not yet been completely loaded, then + * <code>drawImage</code> returns <code>false</code>. As more of + * the image becomes available, the process that draws the image notifies + * the specified image observer. + * @param img the specified image to be drawn. + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + * @param observer object to be notified as more of + * the image is converted. + * @return True if the image has been fully drawn/loaded + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, + ImageObserver observer) { + // System.err.println("drawImage:x, y"); + + final int width = img.getWidth(observer); + final int height = img.getHeight(observer); + if (width == -1 || height == -1) { + return false; + } + + Dimension size = new Dimension(width, height); + BufferedImage buf = buildBufferedImage(size); + + java.awt.Graphics2D g = buf.createGraphics(); + g.setComposite(AlphaComposite.SrcOver); + g.setBackground(new Color(1, 1, 1, 0)); + g.setPaint(new Color(1, 1, 1, 0)); + g.fillRect(0, 0, width, height); + g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight())); + + if (!g.drawImage(img, 0, 0, observer)) { + return false; + } + g.dispose(); + + final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3]; + //final byte[] mask = new byte[buf.getWidth() * buf.getHeight()]; + + Raster raster = buf.getData(); + DataBuffer bd = raster.getDataBuffer(); + + int count = 0; + //int maskpos = 0; + switch (bd.getDataType()) { + case DataBuffer.TYPE_INT: + int[][] idata = ((DataBufferInt)bd).getBankData(); + for (int i = 0; i < idata.length; i++) { + for (int j = 0; j < idata[i].length; j++) { + // mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF); + if (((idata[i][j] >> 24) & 0xFF) != 255) { + result[count++] = (byte)0xFF; + result[count++] = (byte)0xFF; + result[count++] = (byte)0xFF; + } else { + result[count++] = (byte)((idata[i][j] >> 16) & 0xFF); + result[count++] = (byte)((idata[i][j] >> 8) & 0xFF); + result[count++] = (byte)((idata[i][j]) & 0xFF); + } + } + } + break; + default: + // error + break; + } + + /*try { + FopImage fopimg = new TempImage(width, height, result, mask); + AffineTransform at = getTransform(); + double[] matrix = new double[6]; + at.getMatrix(matrix); + psRenderer.write("gsave"); + Shape imclip = getClip(); + writeClip(imclip); + // psRenderer.write("" + matrix[0] + " " + matrix[1] + + // " " + matrix[2] + " " + matrix[3] + " " + + // matrix[4] + " " + matrix[5] + " cm\n"); + //psRenderer.renderBitmap(fopimg, x, y, width, height); + psRenderer.write("grestore"); + } catch (Exception e) { + e.printStackTrace(); + }*/ + return true; + } + + /** + * Creates a buffered image. + * @param size dimensions of the image to be created + * @return the buffered image + */ + public BufferedImage buildBufferedImage(Dimension size) { + return new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_ARGB); + } + + /*class TempImage implements FopImage { + int m_height; + int m_width; + int m_bitsPerPixel; + PDFColorSpace m_colorSpace; + int m_bitmapSiye; + byte[] m_bitmaps; + byte[] m_mask; + PDFColor transparent = new PDFColor(255, 255, 255); + + TempImage(int width, int height, byte[] result, + byte[] mask) { + this.m_height = height; + this.m_width = width; + this.m_bitsPerPixel = 8; + this.m_colorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB); + // this.m_isTransparent = false; + // this.m_bitmapsSize = this.m_width * this.m_height * 3; + this.m_bitmaps = result; + this.m_mask = mask; + } + + public boolean load(int type, FOUserAgent ua) { + return true; + } + + public String getMimeType() { + return ""; + } + + public String getURL() { + return "" + m_bitmaps; + } + + // image size + public int getWidth() { + return m_width; + } + + public int getHeight() { + return m_height; + } + + // DeviceGray, DeviceRGB, or DeviceCMYK + public PDFColorSpace getColorSpace() { + return m_colorSpace; + } + + // bits per pixel + public int getBitsPerPixel() { + return m_bitsPerPixel; + } + + // For transparent images + public boolean isTransparent() { + return transparent != null; + } + + public PDFColor getTransparentColor() { + return transparent; + } + + public boolean hasSoftMask() { + return m_mask != null; + } + + public byte[] getSoftMask() { + return m_mask; + } + + // get the image bytes, and bytes properties + + // get uncompressed image bytes + public byte[] getBitmaps() { + return m_bitmaps; + } + + // width * (bitsPerPixel / 8) * height, no ? + public int getBitmapsSize() { + return m_width * m_height * 3; + } + + // get compressed image bytes + // I don't know if we really need it, nor if it + // should be changed... + public byte[] getRessourceBytes() { + return null; + } + + public int getRessourceBytesSize() { + return 0; + } + + // return null if no corresponding PDFFilter + public PDFFilter getPDFFilter() { + return null; + } + + // release memory + public void close() {} + + }*/ + + + /** + * Draws as much of the specified image as has already been scaled + * to fit inside the specified rectangle. + * <p> + * The image is drawn inside the specified rectangle of this + * graphics context's coordinate space, and is scaled if + * necessary. Transparent pixels do not affect whatever pixels + * are already there. + * <p> + * This method returns immediately in all cases, even if the + * entire image has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete, then + * <code>drawImage</code> returns <code>false</code>. As more of + * the image becomes available, the process that draws the image notifies + * the image observer by calling its <code>imageUpdate</code> method. + * <p> + * A scaled version of an image will not necessarily be + * available immediately just because an unscaled version of the + * image has been constructed for this output device. Each size of + * the image may be cached separately and generated from the original + * data in a separate image production sequence. + * @param img the specified image to be drawn. + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + * @param width the width of the rectangle. + * @param height the height of the rectangle. + * @param observer object to be notified as more of + * the image is converted. + * @return True if the image has been fully loaded/drawn + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) { + System.out.println("drawImage"); + return true; + } + + /** + * Disposes of this graphics context and releases + * any system resources that it is using. + * A <code>Graphics</code> object cannot be used after + * <code>dispose</code>has been called. + * <p> + * When a Java program runs, a large number of <code>Graphics</code> + * objects can be created within a short time frame. + * Although the finalization process of the garbage collector + * also disposes of the same system resources, it is preferable + * to manually free the associated resources by calling this + * method rather than to rely on a finalization process which + * may not run to completion for a long period of time. + * <p> + * Graphics objects which are provided as arguments to the + * <code>paint</code> and <code>update</code> methods + * of components are automatically released by the system when + * those methods return. For efficiency, programmers should + * call <code>dispose</code> when finished using + * a <code>Graphics</code> object only if it was created + * directly from a component or another <code>Graphics</code> object. + * @see java.awt.Graphics#finalize + * @see java.awt.Component#paint + * @see java.awt.Component#update + * @see java.awt.Component#getGraphics + * @see java.awt.Graphics#create + */ + public void dispose() { + // System.out.println("dispose"); + this.gen = null; + fontState = null; + currentFontName = null; + currentColour = null; + fontInfo = null; + } + + /** + * Strokes the outline of a <code>Shape</code> using the settings of the + * current <code>Graphics2D</code> context. The rendering attributes + * applied include the <code>Clip</code>, <code>Transform</code>, + * <code>Paint</code>, <code>Composite</code> and + * <code>Stroke</code> attributes. + * @param s the <code>Shape</code> to be rendered + * @see #setStroke + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #transform + * @see #setTransform + * @see #clip + * @see #setClip + * @see #setComposite + */ + public void draw(Shape s) { + try { + // System.out.println("draw(Shape)"); + gen.saveGraphicsState(); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " " + + gen.formatDouble(c.getGreen() / 255.0) + " " + + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor"); + + applyPaint(getPaint(), false); + applyStroke(getStroke()); + + gen.writeln("newpath"); + PathIterator iter = s.getPathIterator(getTransform()); + while (!iter.isDone()) { + double vals[] = new double[6]; + int type = iter.currentSegment(vals); + switch (type) { + case PathIterator.SEG_CUBICTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " " + + gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + + " curveto"); + break; + case PathIterator.SEG_LINETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " lineto"); + break; + case PathIterator.SEG_MOVETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " M"); + break; + case PathIterator.SEG_QUADTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " QUADTO "); + break; + case PathIterator.SEG_CLOSE: + gen.writeln("closepath"); + break; + default: + break; + } + iter.next(); + } + doDrawing(false, true, false); + gen.restoreGraphicsState(); + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * Establishes a clipping region + * @param s Shape defining the clipping region + */ + protected void writeClip(Shape s) { + try { + PathIterator iter = s.getPathIterator(getTransform()); + gen.writeln("newpath"); + while (!iter.isDone()) { + double vals[] = new double[6]; + int type = iter.currentSegment(vals); + switch (type) { + case PathIterator.SEG_CUBICTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " " + + gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + + " curveto"); + break; + case PathIterator.SEG_LINETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " lineto"); + break; + case PathIterator.SEG_MOVETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " M"); + break; + case PathIterator.SEG_QUADTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " QUADTO "); + break; + case PathIterator.SEG_CLOSE: + gen.writeln("closepath"); + break; + default: + break; + } + iter.next(); + } + // clip area + gen.writeln("clippath"); + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * Applies a new Paint object. + * @param paint Paint object to use + * @param fill True if to be applied for filling + */ + protected void applyPaint(Paint paint, boolean fill) { + if (paint instanceof GradientPaint) { + GradientPaint gp = (GradientPaint)paint; + Color c1 = gp.getColor1(); + Color c2 = gp.getColor2(); + Point2D p1 = gp.getPoint1(); + Point2D p2 = gp.getPoint2(); + //boolean cyclic = gp.isCyclic(); + + List theCoords = new java.util.ArrayList(); + theCoords.add(new Double(p1.getX())); + theCoords.add(new Double(p1.getY())); + theCoords.add(new Double(p2.getX())); + theCoords.add(new Double(p2.getY())); + + List theExtend = new java.util.ArrayList(); + theExtend.add(new Boolean(true)); + theExtend.add(new Boolean(true)); + + List theDomain = new java.util.ArrayList(); + theDomain.add(new Double(0)); + theDomain.add(new Double(1)); + + List theEncode = new java.util.ArrayList(); + theEncode.add(new Double(0)); + theEncode.add(new Double(1)); + theEncode.add(new Double(0)); + theEncode.add(new Double(1)); + + List theBounds = new java.util.ArrayList(); + theBounds.add(new Double(0)); + theBounds.add(new Double(1)); + + //List theFunctions = new java.util.ArrayList(); + + List someColors = new java.util.ArrayList(); + + Color color1 = new Color(c1.getRed(), c1.getGreen(), + c1.getBlue()); + someColors.add(color1); + Color color2 = new Color(c2.getRed(), c2.getGreen(), + c2.getBlue()); + someColors.add(color2); + + //PDFColorSpace aColorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB); + } else if (paint instanceof TexturePaint) { + //nop + } + } + + /** + * Applies a new Stroke object. + * @param stroke Stroke object to use + */ + protected void applyStroke(Stroke stroke) { + try { + if (stroke instanceof BasicStroke) { + BasicStroke bs = (BasicStroke)stroke; + + float[] da = bs.getDashArray(); + if (da != null) { + gen.writeln("["); + for (int count = 0; count < da.length; count++) { + gen.writeln("" + (1000 * (int)da[count])); + if (count < da.length - 1) { + gen.writeln(" "); + } + } + gen.writeln("] "); + float offset = bs.getDashPhase(); + gen.writeln((1000 * (int)offset) + " setdash"); + } + int ec = bs.getEndCap(); + switch (ec) { + case BasicStroke.CAP_BUTT: + gen.writeln(0 + " setlinecap"); + break; + case BasicStroke.CAP_ROUND: + gen.writeln(1 + " setlinecap"); + break; + case BasicStroke.CAP_SQUARE: + gen.writeln(2 + " setlinecap"); + break; + } + + int lj = bs.getLineJoin(); + switch (lj) { + case BasicStroke.JOIN_MITER: + gen.writeln("0 setlinejoin"); + break; + case BasicStroke.JOIN_ROUND: + gen.writeln("1 setlinejoin"); + break; + case BasicStroke.JOIN_BEVEL: + gen.writeln("2 setlinejoin"); + break; + } + float lw = bs.getLineWidth(); + gen.writeln(gen.formatDouble(1000 * lw) + " setlinewidth"); + + float ml = bs.getMiterLimit(); + gen.writeln(gen.formatDouble(1000 * ml) + " setmiterlimit"); + } + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * Renders a {@link RenderedImage}, + * applying a transform from image + * space into user space before drawing. + * The transformation from user space into device space is done with + * the current <code>Transform</code> in the <code>Graphics2D</code>. + * The specified transformation is applied to the image before the + * transform attribute in the <code>Graphics2D</code> context is applied. + * The rendering attributes applied include the <code>Clip</code>, + * <code>Transform</code>, and <code>Composite</code> attributes. Note + * that no rendering is done if the specified transform is + * noninvertible. + * @param img the image to be rendered + * @param xform the transformation from image space into user space + * @see #transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip + */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + System.out.println("drawRenderedImage"); + } + + + /** + * Renders a + * {@link RenderableImage}, + * applying a transform from image space into user space before drawing. + * The transformation from user space into device space is done with + * the current <code>Transform</code> in the <code>Graphics2D</code>. + * The specified transformation is applied to the image before the + * transform attribute in the <code>Graphics2D</code> context is applied. + * The rendering attributes applied include the <code>Clip</code>, + * <code>Transform</code>, and <code>Composite</code> attributes. Note + * that no rendering is done if the specified transform is + * noninvertible. + * <p> + * Rendering hints set on the <code>Graphics2D</code> object might + * be used in rendering the <code>RenderableImage</code>. + * If explicit control is required over specific hints recognized by a + * specific <code>RenderableImage</code>, or if knowledge of which hints + * are used is required, then a <code>RenderedImage</code> should be + * obtained directly from the <code>RenderableImage</code> + * and rendered using + * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}. + * @param img the image to be rendered + * @param xform the transformation from image space into user space + * @see #transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip + * @see #drawRenderedImage + */ + public void drawRenderableImage(RenderableImage img, + AffineTransform xform) { + System.out.println("drawRenderableImage"); + } + + /** + * Renders the text specified by the specified <code>String</code>, + * using the current <code>Font</code> and <code>Paint</code> attributes + * in the <code>Graphics2D</code> context. + * The baseline of the first character is at position + * (<i>x</i>, <i>y</i>) in the User Space. + * The rendering attributes applied include the <code>Clip</code>, + * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and + * <code>Composite</code> attributes. For characters in script systems + * such as Hebrew and Arabic, the glyphs can be rendered from right to + * left, in which case the coordinate supplied is the location of the + * leftmost character on the baseline. + * @param s the <code>String</code> to be rendered + * @param x the x-coordinate where the <code>String</code> + * should be rendered + * @param y the y-coordinate where the <code>String</code> + * should be rendered + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see java.awt.Graphics#setFont + * @see #setTransform + * @see #setComposite + * @see #setClip + */ + public void drawString(String s, float x, float y) { + try { + if (overrideFontState == null) { + Font gFont = getFont(); + String n = gFont.getFamily(); + if (n.equals("sanserif")) { + n = "sans-serif"; + } + int siz = gFont.getSize(); + String style = gFont.isItalic() ? "italic" : "normal"; + String weight = gFont.isBold() ? "bold" : "normal"; + + //try { + //fontState = new FontState(n, fontState.getFontMetrics(),siz); + //} catch (org.apache.fop.apps.FOPException fope) { + //fope.printStackTrace(); + //} + } else { + fontState = overrideFontState; + overrideFontState = null; + } + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(c.getRed() / 255.0 + " " + + c.getGreen() / 255.0 + " " + + c.getBlue() / 255.0 + " setrgbcolor"); + + AffineTransform trans = getTransform(); + trans.translate(x, y); + double[] vals = new double[6]; + trans.getMatrix(vals); + gen.writeln(gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + " moveto "); + //String fontWeight = fontState.getFontWeight(); + StringBuffer sb = new StringBuffer(); + + int l = s.length(); + + if ((currentFontName != fontState.getFontName()) + || (currentFontSize != fontState.getFontSize())) { + gen.writeln(fontState.getFontName() + " " + fontState.getFontSize() + " F"); + currentFontName = fontState.getFontName(); + currentFontSize = fontState.getFontSize(); + } + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + char mch = fontState.mapChar(ch); + if (mch > 127) { + sb = sb.append("\\" + Integer.toOctalString(mch)); + } else { + String escape = "\\()[]{}"; + if (escape.indexOf(mch) >= 0) { + sb.append("\\"); + } + sb = sb.append(mch); + } + } + + String psString = null; + psString = " (" + sb.toString() + ") " + " t "; + + gen.writeln(" 1.0 -1.0 scale"); + gen.writeln(psString); + gen.writeln(" 1.0 -1.0 scale"); + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * Renders the text of the specified iterator, using the + * <code>Graphics2D</code> context's current <code>Paint</code>. The + * iterator must specify a font + * for each character. The baseline of the + * first character is at position (<i>x</i>, <i>y</i>) in the + * User Space. + * The rendering attributes applied include the <code>Clip</code>, + * <code>Transform</code>, <code>Paint</code>, and + * <code>Composite</code> attributes. + * For characters in script systems such as Hebrew and Arabic, + * the glyphs can be rendered from right to left, in which case the + * coordinate supplied is the location of the leftmost character + * on the baseline. + * @param iterator the iterator whose text is to be rendered + * @param x the x-coordinate where the iterator's text is to be + * rendered + * @param y the y-coordinate where the iterator's text is to be + * rendered + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #setTransform + * @see #setComposite + * @see #setClip + */ + public void drawString(AttributedCharacterIterator iterator, float x, + float y) { + try { + System.err.println("drawString(AttributedCharacterIterator)"); + + gen.writeln("BT"); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + currentColour = new Color(c.getRed(), c.getGreen(), c.getBlue()); + //gen.writeln(currentColour.getColorSpaceOut(true)); + c = getBackground(); + Color col = new Color(c.getRed(), c.getGreen(), c.getBlue()); + //gen.writeln(col.getColorSpaceOut(false)); + + AffineTransform trans = getTransform(); + trans.translate(x, y); + double[] vals = new double[6]; + trans.getMatrix(vals); + + for (char ch = iterator.first(); ch != CharacterIterator.DONE; + ch = iterator.next()) { + //Map attr = iterator.getAttributes(); + + gen.writeln(gen.formatDouble(vals[0]) + " " + + gen.formatDouble(vals[1]) + " " + + gen.formatDouble(vals[2]) + " " + + gen.formatDouble(vals[3]) + " " + + gen.formatDouble(vals[4]) + " " + + gen.formatDouble(vals[5]) + " " + + gen.formatDouble(vals[6]) + " Tm [" + ch + + "]"); + } + + gen.writeln("ET"); + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * Fills the interior of a <code>Shape</code> using the settings of the + * <code>Graphics2D</code> context. The rendering attributes applied + * include the <code>Clip</code>, <code>Transform</code>, + * <code>Paint</code>, and <code>Composite</code>. + * @param s the <code>Shape</code> to be filled + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip + */ + public void fill(Shape s) { + try { + // System.err.println("fill"); + gen.writeln("gsave"); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " " + + gen.formatDouble(c.getGreen() / 255.0) + " " + + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor"); + + applyPaint(getPaint(), true); + + gen.writeln("newpath"); + PathIterator iter = s.getPathIterator(getTransform()); + while (!iter.isDone()) { + double vals[] = new double[6]; + int type = iter.currentSegment(vals); + switch (type) { + case PathIterator.SEG_CUBICTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " " + + gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + + " curveto"); + break; + case PathIterator.SEG_LINETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " lineto"); + break; + case PathIterator.SEG_MOVETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " M"); + break; + case PathIterator.SEG_QUADTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " QUADTO "); + break; + case PathIterator.SEG_CLOSE: + gen.writeln("closepath"); + break; + default: + break; + } + iter.next(); + } + doDrawing(true, false, + iter.getWindingRule() == PathIterator.WIND_EVEN_ODD); + gen.writeln("grestore"); + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * Commits a painting operation. + * @param fill filling + * @param stroke stroking + * @param nonzero ??? + * @exception IOException In case of an I/O problem + */ + protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) + throws IOException { + if (fill) { + if (stroke) { + if (!nonzero) { + gen.writeln("stroke"); + } else { + gen.writeln("stroke"); + } + } else { + if (!nonzero) { + gen.writeln("fill"); + } else { + gen.writeln("fill"); + } + } + } else { + // if(stroke) + gen.writeln("stroke"); + } + } + + /** + * Returns the device configuration associated with this + * <code>Graphics2D</code>. + * @return the device configuration + */ + public GraphicsConfiguration getDeviceConfiguration() { + // System.out.println("getDeviceConviguration"); + return GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + } + + /** + * Used to create proper font metrics + */ + private Graphics2D fmg; + + { + BufferedImage bi = new BufferedImage(1, 1, + BufferedImage.TYPE_INT_ARGB); + + fmg = bi.createGraphics(); + } + + /** + * Sets the overrideing font state. + * @param infont FontState to set + */ + public void setOverrideFontState(FontState infont) { + overrideFontState = infont; + } + + /** + * Gets the font metrics for the specified font. + * @return the font metrics for the specified font. + * @param f the specified font + * @see java.awt.Graphics#getFont + * @see java.awt.FontMetrics + * @see java.awt.Graphics#getFontMetrics() + */ + public java.awt.FontMetrics getFontMetrics(Font f) { + return fmg.getFontMetrics(f); + } + + /** + * Sets the paint mode of this graphics context to alternate between + * this graphics context's current color and the new specified color. + * This specifies that logical pixel operations are performed in the + * XOR mode, which alternates pixels between the current color and + * a specified XOR color. + * <p> + * When drawing operations are performed, pixels which are the + * current color are changed to the specified color, and vice versa. + * <p> + * Pixels that are of colors other than those two colors are changed + * in an unpredictable but reversible manner; if the same figure is + * drawn twice, then all pixels are restored to their original values. + * @param c1 the XOR alternation color + */ + public void setXORMode(Color c1) { + System.out.println("setXORMode"); + } + + + /** + * Copies an area of the component by a distance specified by + * <code>dx</code> and <code>dy</code>. From the point specified + * by <code>x</code> and <code>y</code>, this method + * copies downwards and to the right. To copy an area of the + * component to the left or upwards, specify a negative value for + * <code>dx</code> or <code>dy</code>. + * If a portion of the source rectangle lies outside the bounds + * of the component, or is obscured by another window or component, + * <code>copyArea</code> will be unable to copy the associated + * pixels. The area that is omitted can be refreshed by calling + * the component's <code>paint</code> method. + * @param x the <i>x</i> coordinate of the source rectangle. + * @param y the <i>y</i> coordinate of the source rectangle. + * @param width the width of the source rectangle. + * @param height the height of the source rectangle. + * @param dx the horizontal distance to copy the pixels. + * @param dy the vertical distance to copy the pixels. + */ + public void copyArea(int x, int y, int width, int height, int dx, + int dy) { + System.out.println("copyArea"); + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSProcSets.java b/src/java/org/apache/fop/render/ps/PSProcSets.java new file mode 100644 index 000000000..566328733 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSProcSets.java @@ -0,0 +1,200 @@ +/* + * $Id: PSProcSets.java,v 1.3 2003/03/11 08:42:24 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.IOException; + +/** + * This class defines the basic resources (procsets) used by FOP's PostScript + * renderer and SVG transcoder. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> + * @version $Id: PSProcSets.java,v 1.3 2003/03/11 08:42:24 jeremias Exp $ + */ +public final class PSProcSets { + + /** + * Generates a resource defining standard procset for FOP. + * @param gen PSGenerator to use for output + * @throws IOException In case of an I/O problem + */ + public static final void writeFOPStdProcSet(PSGenerator gen) throws IOException { + gen.writeln("%%BeginResource: procset (Apache FOP Std ProcSet) 1.0 0"); + gen.writeln("%%Version: 1.0 0"); + gen.writeln("%%Copyright: Copyright (C) 2001-2003 " + + "The Apache Software Foundation. All rights reserved."); + gen.writeln("%%Title: Basic set of procedures used by FOP"); + + gen.writeln("/bd{bind def}bind def"); + gen.writeln("/ld{load def}bd"); + gen.writeln("/M/moveto ld"); + gen.writeln("/RM/rmoveto ld"); + gen.writeln("/t/show ld"); + + gen.writeln("/_ctm matrix def"); //Holds the current matrix + gen.writeln("/_tm matrix def"); + //BT: save currentmatrix, set _tm to identitymatrix and move to 0/0 + gen.writeln("/BT { _ctm currentmatrix pop matrix _tm copy pop 0 0 moveto } bd"); + //ET: restore last currentmatrix + gen.writeln("/ET { _ctm setmatrix } bd"); + gen.writeln("/iTm { _ctm setmatrix _tm concat } bd"); + gen.writeln("/Tm { _tm astore pop iTm 0 0 moveto } bd"); + + gen.writeln("/ux 0.0 def"); + gen.writeln("/uy 0.0 def"); + + // <font> <size> F + gen.writeln("/F {"); + gen.writeln(" /Tp exch def"); + // gen.writeln(" currentdict exch get"); + gen.writeln(" /Tf exch def"); + gen.writeln(" Tf findfont Tp scalefont setfont"); + gen.writeln(" /cf Tf def /cs Tp def /cw ( ) stringwidth pop def"); + gen.writeln("} bd"); + + gen.writeln("/ULS {currentpoint /uy exch def /ux exch def} bd"); + gen.writeln("/ULE {"); + gen.writeln(" /Tcx currentpoint pop def"); + gen.writeln(" gsave"); + gen.writeln(" newpath"); + gen.writeln(" cf findfont cs scalefont dup"); + gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); + gen.writeln(" /UnderlinePosition get Ts mul /To exch def"); + gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def"); + gen.writeln(" ux uy To add moveto Tcx uy To add lineto"); + gen.writeln(" Tt setlinewidth stroke"); + gen.writeln(" grestore"); + gen.writeln("} bd"); + + gen.writeln("/OLE {"); + gen.writeln(" /Tcx currentpoint pop def"); + gen.writeln(" gsave"); + gen.writeln(" newpath"); + gen.writeln(" cf findfont cs scalefont dup"); + gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); + gen.writeln(" /UnderlinePosition get Ts mul /To exch def"); + gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def"); + gen.writeln(" ux uy To add cs add moveto Tcx uy To add cs add lineto"); + gen.writeln(" Tt setlinewidth stroke"); + gen.writeln(" grestore"); + gen.writeln("} bd"); + + gen.writeln("/SOE {"); + gen.writeln(" /Tcx currentpoint pop def"); + gen.writeln(" gsave"); + gen.writeln(" newpath"); + gen.writeln(" cf findfont cs scalefont dup"); + gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); + gen.writeln(" /UnderlinePosition get Ts mul /To exch def"); + gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def"); + gen.writeln(" ux uy To add cs 10 mul 26 idiv add moveto " + + "Tcx uy To add cs 10 mul 26 idiv add lineto"); + gen.writeln(" Tt setlinewidth stroke"); + gen.writeln(" grestore"); + gen.writeln("} bd"); + + gen.writeln("/QUADTO {"); + gen.writeln("/Y22 exch store"); + gen.writeln("/X22 exch store"); + gen.writeln("/Y21 exch store"); + gen.writeln("/X21 exch store"); + gen.writeln("currentpoint"); + gen.writeln("/Y21 load 2 mul add 3 div exch"); + gen.writeln("/X21 load 2 mul add 3 div exch"); + gen.writeln("/X21 load 2 mul /X22 load add 3 div"); + gen.writeln("/Y21 load 2 mul /Y22 load add 3 div"); + gen.writeln("/X22 load /Y22 load curveto"); + gen.writeln("} bd"); + + gen.writeln("%%EndResource"); + } + + + /** + * Generates a resource defining a procset for including EPS graphics. + * @param gen PSGenerator to use for output + * @throws IOException In case of an I/O problem + */ + public static final void writeFOPEPSProcSet(PSGenerator gen) throws IOException { + gen.writeln("%%BeginResource: procset (Apache FOP EPS ProcSet) 1.0 0"); + gen.writeln("%%Version: 1.0 0"); + gen.writeln("%%Copyright: Copyright (C) 2002-2003 " + + "The Apache Software Foundation. All rights reserved."); + gen.writeln("%%Title: EPS procedures used by FOP"); + + gen.writeln("/BeginEPSF { %def"); + gen.writeln("/b4_Inc_state save def % Save state for cleanup"); + gen.writeln("/dict_count countdictstack def % Count objects on dict stack"); + gen.writeln("/op_count count 1 sub def % Count objects on operand stack"); + gen.writeln("userdict begin % Push userdict on dict stack"); + gen.writeln("/showpage { } def % Redefine showpage, { } = null proc"); + gen.writeln("0 setgray 0 setlinecap % Prepare graphics state"); + gen.writeln("1 setlinewidth 0 setlinejoin"); + gen.writeln("10 setmiterlimit [ ] 0 setdash newpath"); + gen.writeln("/languagelevel where % If level not equal to 1 then"); + gen.writeln("{pop languagelevel % set strokeadjust and"); + gen.writeln("1 ne % overprint to their defaults."); + gen.writeln("{false setstrokeadjust false setoverprint"); + gen.writeln("} if"); + gen.writeln("} if"); + gen.writeln("} bd"); + + gen.writeln("/EndEPSF { %def"); + gen.writeln("count op_count sub {pop} repeat % Clean up stacks"); + gen.writeln("countdictstack dict_count sub {end} repeat"); + gen.writeln("b4_Inc_state restore"); + gen.writeln("} bd"); + + gen.writeln("%%EndResource"); + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java new file mode 100644 index 000000000..9e22812ed --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -0,0 +1,901 @@ +/* + * $Id: PSRenderer.java,v 1.31 2003/03/11 08:42:24 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +// Java +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +// FOP +import org.apache.fop.fo.properties.BackgroundRepeat; +import org.apache.fop.area.Area; +import org.apache.fop.area.RegionViewport; +import org.apache.fop.apps.FOPException; +import org.apache.fop.area.Block; +import org.apache.fop.area.BlockViewport; +import org.apache.fop.area.CTM; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.ForeignObject; +import org.apache.fop.area.inline.Word; +import org.apache.fop.datatypes.ColorType; +import org.apache.fop.fo.FOUserAgent; +import org.apache.fop.fonts.Font; +import org.apache.fop.layout.FontInfo; +import org.apache.fop.render.AbstractRenderer; +import org.apache.fop.render.RendererContext; + +import org.apache.fop.image.FopImage; +import org.apache.fop.image.ImageFactory; +import org.apache.fop.traits.BorderProps; + +import org.w3c.dom.Document; +/** + * Renderer that renders to PostScript. + * <br> + * This class currently generates PostScript Level 2 code. The only exception + * is the FlateEncode filter which is a Level 3 feature. The filters in use + * are hardcoded at the moment. + * <br> + * This class follows the Document Structuring Conventions (DSC) version 3.0. + * If anyone modifies this renderer please make + * sure to also follow the DSC to make it simpler to programmatically modify + * the generated Postscript files (ex. extract pages etc.). + * <br> + * The PS renderer operates in millipoints as the layout engine. Since PostScript + * initially uses points, scaling is applied as needed. + * @todo Rebuild the PostScript renderer + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> + * @version $Id: PSRenderer.java,v 1.31 2003/03/11 08:42:24 jeremias Exp $ + */ +public class PSRenderer extends AbstractRenderer { + + /** The MIME type for PostScript */ + public static final String MIME_TYPE = "application/postscript"; + + /** The application producing the PostScript */ + protected String producer; + private int currentPageNumber = 0; + + private boolean enableComments = true; + + /** The PostScript generator used to output the PostScript */ + protected PSGenerator gen; + private boolean ioTrouble = false; + + private String currentFontName; + private int currentFontSize; + private int pageHeight; + private int pageWidth; + private float currRed; + private float currGreen; + private float currBlue; + + private FontInfo fontInfo; + + /** + * Set the document's producer + * + * @param producer string indicating application producing the PostScript + */ + public void setProducer(String producer) { + this.producer = producer; + } + + /** + * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent) + */ + public void setUserAgent(FOUserAgent agent) { + super.setUserAgent(agent); + PSXMLHandler xmlHandler = new PSXMLHandler(); + //userAgent.setDefaultXMLHandler(MIME_TYPE, xmlHandler); + String svg = "http://www.w3.org/2000/svg"; + userAgent.addXMLHandler(MIME_TYPE, svg, xmlHandler); + } + + /** + * Write out a command + * @param cmd PostScript command + */ + protected void writeln(String cmd) { + try { + gen.writeln(cmd); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** + * Central exception handler for I/O exceptions. + * @param ioe IOException to handle + */ + protected void handleIOTrouble(IOException ioe) { + if (!ioTrouble) { + getLogger().error("Error while writing to target file", ioe); + ioTrouble = true; + } + } + + /** + * Write out a comment + * @param comment Comment to write + */ + protected void comment(String comment) { + if (this.enableComments) { + writeln(comment); + } + } + + /** + * Generates the PostScript code for the font dictionary. + * @param fontInfo available fonts + */ + protected void writeFontDict(FontInfo fontInfo) { + writeln("%%BeginResource: procset FOPFonts"); + writeln("%%Title: Font setup (shortcuts) for this file"); + writeln("/FOPFonts 100 dict dup begin"); + + // write("/gfF1{/Helvetica findfont} bd"); + // write("/gfF3{/Helvetica-Bold findfont} bd"); + Map fonts = fontInfo.getFonts(); + Iterator enum = fonts.keySet().iterator(); + while (enum.hasNext()) { + String key = (String)enum.next(); + Font fm = (Font)fonts.get(key); + writeln("/" + key + " /" + fm.getFontName() + " def"); + } + writeln("end def"); + writeln("%%EndResource"); + enum = fonts.keySet().iterator(); + while (enum.hasNext()) { + String key = (String)enum.next(); + Font fm = (Font)fonts.get(key); + writeln("/" + fm.getFontName() + " findfont"); + writeln("dup length dict begin"); + writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); + writeln(" /Encoding ISOLatin1Encoding def"); + writeln(" currentdict"); + writeln("end"); + writeln("/" + fm.getFontName() + " exch definefont pop"); + } + } + + /** + * Make sure the cursor is in the right place. + */ + protected void movetoCurrPosition() { + moveTo(this.currentIPPosition, this.currentBPPosition); + } + + /** + * Moves the cursor. + * @param x X coordinate + * @param y Y coordinate + */ + protected void moveTo(int x, int y) { + writeln(x + " " + y + " M"); + } + + /** Saves the graphics state of the rendering engine. */ + public void saveGraphicsState() { + try { + //delegate + gen.saveGraphicsState(); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** Restores the last graphics state of the rendering engine. */ + public void restoreGraphicsState() { + try { + //delegate + gen.restoreGraphicsState(); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** Indicates the beginning of a text object. */ + protected void beginTextObject() { + writeln("BT"); + } + + /** Indicates the end of a text object. */ + protected void endTextObject() { + writeln("ET"); + } + + /** + * Concats the transformation matrix. + * @param a A part + * @param b B part + * @param c C part + * @param d D part + * @param e E part + * @param f F part + */ + protected void concatMatrix(double a, double b, + double c, double d, + double e, double f) { + try { + gen.concatMatrix(a, b, c, d, e, f); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** + * Concats the transformations matrix. + * @param matrix Matrix to use + */ + protected void concatMatrix(double[] matrix) { + try { + gen.concatMatrix(matrix); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** + * Set up the font info + * + * @param fontInfo the font info object to set up + */ + public void setupFontInfo(FontInfo fontInfo) { + /* use PDF's font setup to get PDF metrics */ + org.apache.fop.render.pdf.FontSetup.setup(fontInfo, null); + this.fontInfo = fontInfo; + } + + /** + * Draws a filled rectangle. + * @param x x-coordinate + * @param y y-coordinate + * @param w width + * @param h height + * @param col color to fill with + */ + protected void fillRect(int x, int y, int w, int h, + ColorType col) { + useColor(col); + writeln(x + " " + y + " " + w + " " + h + " rectfill"); + } + + /** + * Draws a stroked rectangle with the current stroke settings. + * @param x x-coordinate + * @param y y-coordinate + * @param w width + * @param h height + */ + protected void drawRect(int x, int y, int w, int h) { + writeln(x + " " + y + " " + w + " " + h + " rectstroke"); + } + + /** + * Clip an area. + * Write a clipping operation given coordinates in the current + * transform. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the area + * @param height the height of the area + */ + protected void clip(float x, float y, float width, float height) { + writeln(x + " " + y + " " + width + " " + height + " rectclip"); + } + + /** + * Changes the currently used font. + * @param name name of the font + * @param size font size + */ + public void useFont(String name, int size) { + if ((currentFontName != name) || (currentFontSize != size)) { + writeln(name + " " + size + " F"); + currentFontName = name; + currentFontSize = size; + } + } + + private void useColor(ColorType col) { + useColor(col.getRed(), col.getGreen(), col.getBlue()); + } + + private void useColor(float red, float green, float blue) { + if ((red != currRed) || (green != currGreen) || (blue != currBlue)) { + writeln(red + " " + green + " " + blue + " setrgbcolor"); + currRed = red; + currGreen = green; + currBlue = blue; + } + } + + /** + * @see org.apache.fop.render.Renderer#startRenderer(OutputStream) + */ + public void startRenderer(OutputStream outputStream) + throws IOException { + getLogger().debug("rendering areas to PostScript"); + + //Setup for PostScript generation + this.gen = new PSGenerator(outputStream); + this.currentPageNumber = 0; + + //PostScript Header + writeln(DSCConstants.PS_ADOBE_30); + gen.writeDSCComment(DSCConstants.CREATOR, new String[] {"FOP " + this.producer}); + gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()}); + gen.writeDSCComment(DSCConstants.PAGES, new Object[] {PSGenerator.ATEND}); + gen.writeDSCComment(DSCConstants.END_COMMENTS); + + //Defaults + gen.writeDSCComment(DSCConstants.BEGIN_DEFAULTS); + gen.writeDSCComment(DSCConstants.END_DEFAULTS); + + //Prolog + gen.writeDSCComment(DSCConstants.BEGIN_PROLOG); + gen.writeDSCComment(DSCConstants.END_PROLOG); + + //Setup + gen.writeDSCComment(DSCConstants.BEGIN_SETUP); + PSProcSets.writeFOPStdProcSet(gen); + PSProcSets.writeFOPEPSProcSet(gen); + writeFontDict(fontInfo); + gen.writeDSCComment(DSCConstants.END_SETUP); + } + + /** + * @see org.apache.fop.render.Renderer#stopRenderer() + */ + public void stopRenderer() throws IOException { + gen.writeDSCComment(DSCConstants.TRAILER); + gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.currentPageNumber)); + gen.writeDSCComment(DSCConstants.EOF); + gen.flush(); + } + + /** + * @see org.apache.fop.render.Renderer#renderPage(PageViewport) + */ + public void renderPage(PageViewport page) + throws IOException, FOPException { + getLogger().debug("renderPage(): " + page); + + this.currentPageNumber++; + gen.writeDSCComment(DSCConstants.PAGE, new Object[] + {page.getPageNumber(), + new Integer(this.currentPageNumber)}); + final Integer zero = new Integer(0); + final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth())); + final Long pageheight = new Long(Math.round(page.getViewArea().getHeight())); + gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] + {zero, zero, pagewidth, pageheight}); + gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP); + gen.writeln("FOPFonts begin"); + gen.writeln("0.001 0.001 scale"); + concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue()); + + gen.writeDSCComment(DSCConstants.END_PAGE_SETUP); + + //Process page + super.renderPage(page); + + writeln("showpage"); + gen.writeDSCComment(DSCConstants.PAGE_TRAILER); + gen.writeDSCComment(DSCConstants.END_PAGE); + } + + /** + * Paints text. + * @param rx X coordinate + * @param bl Y coordinate + * @param text Text to paint + * @param font Font to use + */ + protected void paintText(int rx, int bl, String text, Font font) { + saveGraphicsState(); + writeln("1 0 0 -1 " + rx + " " + bl + " Tm"); + + int initialSize = text.length(); + initialSize += initialSize / 2; + StringBuffer sb = new StringBuffer(initialSize); + sb.append("("); + for (int i = 0; i < text.length(); i++) { + final char c = text.charAt(i); + final char mapped = font.mapChar(c); + gen.escapeChar(mapped, sb); + } + sb.append(") t"); + writeln(sb.toString()); + restoreGraphicsState(); + } + + /** + * @see org.apache.fop.render.Renderer#renderWord(Word) + */ + public void renderWord(Word area) { + String fontname = (String)area.getTrait(Trait.FONT_NAME); + int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE); + + // This assumes that *all* CIDFonts use a /ToUnicode mapping + Font f = (Font)fontInfo.getFonts().get(fontname); + + //Determine position + int rx = currentBlockIPPosition; + int bl = currentBPPosition + area.getOffset(); + + useFont(fontname, fontsize); + + paintText(rx, bl, area.getWord(), f); + +/* + String psString = null; + if (area.getFontState().getLetterSpacing() > 0) { + //float f = area.getFontState().getLetterSpacing() + // * 1000 / this.currentFontSize; + float f = area.getFontState().getLetterSpacing(); + psString = (new StringBuffer().append(f).append(" 0.0 (") + .append(sb.toString()).append(") A")).toString(); + } else { + psString = (new StringBuffer("(").append(sb.toString()) + .append(") t")).toString(); + } + + + // System.out.println("["+s+"] --> ["+sb.toString()+"]"); + + // comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString()); + useFont(fs.getFontName(), fs.getFontSize()); + useColor(area.getRed(), area.getGreen(), area.getBlue()); + if (area.getUnderlined() || area.getLineThrough() + || area.getOverlined()) + write("ULS"); + write(psString); + if (area.getUnderlined()) + write("ULE"); + if (area.getLineThrough()) + write("SOE"); + if (area.getOverlined()) + write("OLE"); + this.currentXPosition += area.getContentWidth(); + */ + super.renderWord(area); //Updates IPD + } + + + /** + * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List) + */ + protected void renderBlockViewport(BlockViewport bv, List children) { + // clip and position viewport if necessary + + // save positions + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + String saveFontName = currentFontName; + + CTM ctm = bv.getCTM(); + + if (bv.getPositioning() == Block.ABSOLUTE) { + + currentIPPosition = 0; + currentBPPosition = 0; + + //closeText(); + endTextObject(); + + if (bv.getClip()) { + saveGraphicsState(); + int x = bv.getXOffset() + containingIPPosition; + int y = bv.getYOffset() + containingBPPosition; + int width = bv.getWidth(); + int height = bv.getHeight(); + clip(x, y, width, height); + } + + CTM tempctm = new CTM(containingIPPosition, containingBPPosition); + ctm = tempctm.multiply(ctm); + + startVParea(ctm); + handleBlockTraits(bv); + renderBlocks(children); + endVParea(); + + if (bv.getClip()) { + restoreGraphicsState(); + } + beginTextObject(); + + // clip if necessary + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + } else { + + if (ctm != null) { + currentIPPosition = 0; + currentBPPosition = 0; + + //closeText(); + endTextObject(); + + double[] vals = ctm.toArray(); + //boolean aclock = vals[2] == 1.0; + if (vals[2] == 1.0) { + ctm = ctm.translate(-saveBP - bv.getHeight(), -saveIP); + } else if (vals[0] == -1.0) { + ctm = ctm.translate(-saveIP - bv.getWidth(), -saveBP - bv.getHeight()); + } else { + ctm = ctm.translate(saveBP, saveIP - bv.getWidth()); + } + } + + // clip if necessary + if (bv.getClip()) { + if (ctm == null) { + //closeText(); + endTextObject(); + } + saveGraphicsState(); + int x = bv.getXOffset(); + int y = bv.getYOffset(); + int width = bv.getWidth(); + int height = bv.getHeight(); + clip(x, y, width, height); + } + + if (ctm != null) { + startVParea(ctm); + } + handleBlockTraits(bv); + renderBlocks(children); + if (ctm != null) { + endVParea(); + } + + if (bv.getClip()) { + restoreGraphicsState(); + if (ctm == null) { + beginTextObject(); + } + } + if (ctm != null) { + beginTextObject(); + } + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + currentBPPosition += (int)(bv.getHeight()); + } + currentFontName = saveFontName; + } + + /** + * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM) + */ + protected void startVParea(CTM ctm) { + // Set the given CTM in the graphics state + //currentState.push(); + //currentState.setTransform(new AffineTransform(CTMHelper.toPDFArray(ctm))); + + saveGraphicsState(); + // multiply with current CTM + //writeln(CTMHelper.toPDFString(ctm) + " cm\n"); + final double matrix[] = ctm.toArray(); + concatMatrix(matrix); + + // Set clip? + beginTextObject(); + } + + /** + * @see org.apache.fop.render.AbstractRenderer#endVParea() + */ + protected void endVParea() { + endTextObject(); + restoreGraphicsState(); + //currentState.pop(); + } + + /** + * Handle the viewport traits. + * This is used to draw the traits for a viewport. + * + * @param region the viewport region to handle + */ + protected void handleViewportTraits(RegionViewport region) { + currentFontName = ""; + float startx = 0; + float starty = 0; + Rectangle2D viewArea = region.getViewArea(); + float width = (float)(viewArea.getWidth()); + float height = (float)(viewArea.getHeight()); + /* + Trait.Background back; + back = (Trait.Background)region.getTrait(Trait.BACKGROUND); + */ + drawBackAndBorders(region, startx, starty, width, height); + } + + /** + * Handle block traits. + * The block could be any sort of block with any positioning + * so this should render the traits such as border and background + * in its position. + * + * @param block the block to render the traits + */ + protected void handleBlockTraits(Block block) { + float startx = currentIPPosition; + float starty = currentBPPosition; + drawBackAndBorders(block, startx, starty, + block.getWidth(), block.getHeight()); + } + + /** + * Draw the background and borders. + * This draws the background and border traits for an area given + * the position. + * + * @param block the area to get the traits from + * @param startx the start x position + * @param starty the start y position + * @param width the width of the area + * @param height the height of the area + */ + protected void drawBackAndBorders(Area block, + float startx, float starty, + float width, float height) { + // draw background then border + + boolean started = false; + Trait.Background back; + back = (Trait.Background)block.getTrait(Trait.BACKGROUND); + if (back != null) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + + if (back.getColor() != null) { + updateColor(back.getColor(), true, null); + writeln(startx + " " + starty + " " + + width + " " + height + " rectfill"); + } + if (back.getURL() != null) { + ImageFactory fact = ImageFactory.getInstance(); + FopImage fopimage = fact.getImage(back.getURL(), userAgent); + if (fopimage != null && fopimage.load(FopImage.DIMENSIONS, userAgent)) { + if (back.getRepeat() == BackgroundRepeat.REPEAT) { + // create a pattern for the image + } else { + // place once + Rectangle2D pos; + pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000, + (starty + back.getVertical()) * 1000, + fopimage.getWidth() * 1000, + fopimage.getHeight() * 1000); + // putImage(back.url, pos); + } + } + } + } + + BorderProps bps = (BorderProps)block.getTrait(Trait.BORDER_BEFORE); + if (bps != null) { + float endx = startx + width; + + if (!started) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + + drawLine(startx, starty + bwidth / 2, endx, starty + bwidth / 2); + } + bps = (BorderProps)block.getTrait(Trait.BORDER_START); + if (bps != null) { + float endy = starty + height; + + if (!started) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + + drawLine(startx + bwidth / 2, starty, startx + bwidth / 2, endy); + } + bps = (BorderProps)block.getTrait(Trait.BORDER_AFTER); + if (bps != null) { + float sy = starty + height; + float endx = startx + width; + + if (!started) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + + drawLine(startx, sy - bwidth / 2, endx, sy - bwidth / 2); + } + bps = (BorderProps)block.getTrait(Trait.BORDER_END); + if (bps != null) { + float sx = startx + width; + float endy = starty + height; + + if (!started) { + started = true; + // closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + drawLine(sx - bwidth / 2, starty, sx - bwidth / 2, endy); + } + if (started) { + //restoreGraphicsState(); + beginTextObject(); + // font last set out of scope in text section + currentFontName = ""; + } + } + + /** + * Draw a line. + * + * @param startx the start x position + * @param starty the start y position + * @param endx the x end position + * @param endy the y end position + */ + private void drawLine(float startx, float starty, float endx, float endy) { + writeln(startx + " " + starty + " M "); + writeln(endx + " " + endy + " lineto"); + } + + private void updateColor(ColorType col, boolean fill, StringBuffer pdf) { + writeln(gen.formatDouble(col.getRed()) + " " + + gen.formatDouble(col.getGreen()) + " " + + gen.formatDouble(col.getBlue()) + " setrgbcolor"); + } + + private void updateFont(String name, int size, StringBuffer pdf) { + + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) + */ + public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { + Document doc = fo.getDocument(); + String ns = fo.getNameSpace(); + renderDocument(doc, ns, pos); + } + + /** + * Renders an XML document (SVG for example). + * @param doc DOM Document containing the XML document to be rendered + * @param ns Namespace for the XML document + * @param pos Position for the generated graphic/image + */ + public void renderDocument(Document doc, String ns, Rectangle2D pos) { + RendererContext context; + context = new RendererContext(MIME_TYPE); + context.setUserAgent(userAgent); + + context.setProperty(PSXMLHandler.PS_GENERATOR, this.gen); + context.setProperty(PSXMLHandler.PS_FONT_INFO, fontInfo); + context.setProperty(PSXMLHandler.PS_WIDTH, + new Integer((int) pos.getWidth())); + context.setProperty(PSXMLHandler.PS_HEIGHT, + new Integer((int) pos.getHeight())); + context.setProperty(PSXMLHandler.PS_XPOS, + new Integer(currentBlockIPPosition + (int) pos.getX())); + context.setProperty(PSXMLHandler.PS_YPOS, + new Integer(currentBPPosition + (int) pos.getY())); + //context.setProperty("strokeSVGText", options.get("strokeSVGText")); + + /* + context.setProperty(PDFXMLHandler.PDF_DOCUMENT, pdfDoc); + context.setProperty(PDFXMLHandler.OUTPUT_STREAM, ostream); + context.setProperty(PDFXMLHandler.PDF_STATE, currentState); + context.setProperty(PDFXMLHandler.PDF_PAGE, currentPage); + context.setProperty(PDFXMLHandler.PDF_CONTEXT, + currentContext == null ? currentPage: currentContext); + context.setProperty(PDFXMLHandler.PDF_CONTEXT, currentContext); + context.setProperty(PDFXMLHandler.PDF_STREAM, currentStream); + context.setProperty(PDFXMLHandler.PDF_XPOS, + new Integer(currentBlockIPPosition + (int) pos.getX())); + context.setProperty(PDFXMLHandler.PDF_YPOS, + new Integer(currentBPPosition + (int) pos.getY())); + context.setProperty(PDFXMLHandler.PDF_FONT_INFO, fontInfo); + context.setProperty(PDFXMLHandler.PDF_FONT_NAME, currentFontName); + context.setProperty(PDFXMLHandler.PDF_FONT_SIZE, + new Integer(currentFontSize)); + context.setProperty(PDFXMLHandler.PDF_WIDTH, + new Integer((int) pos.getWidth())); + context.setProperty(PDFXMLHandler.PDF_HEIGHT, + new Integer((int) pos.getHeight())); + */ + userAgent.renderXML(context, doc, ns); + + } + + + + +} diff --git a/src/java/org/apache/fop/render/ps/PSState.java b/src/java/org/apache/fop/render/ps/PSState.java new file mode 100644 index 000000000..32daaee53 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSState.java @@ -0,0 +1,97 @@ +/* + * $Id: PSState.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.Serializable; +import java.awt.geom.AffineTransform; + +/** + * This class holds the current state of the PostScript interpreter. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> + * @version $Id: PSState.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + */ +public class PSState implements Serializable, Cloneable { + + private AffineTransform transform = new AffineTransform(); + + + + /** + * Returns the transform. + * @return the current transformation matrix + */ + public AffineTransform getTransform() { + return this.transform; + } + + /** + * Concats the given transformation matrix with the current one. + * @param transform The new transformation matrix + */ + public void concatMatrix(AffineTransform transform) { + this.transform.concatenate(transform); + } + + /** + * @see java.lang.Object#clone() + */ + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSTextElementBridge.java b/src/java/org/apache/fop/render/ps/PSTextElementBridge.java new file mode 100644 index 000000000..e7bc31fe8 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSTextElementBridge.java @@ -0,0 +1,159 @@ +/* + * $Id: PSTextElementBridge.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +//import org.apache.batik.gvt.TextNode; +import org.apache.batik.bridge.SVGTextElementBridge; +import org.apache.batik.bridge.BridgeContext; +//import org.apache.batik.bridge.TextUtilities; +import org.apache.batik.gvt.GraphicsNode; + +import org.apache.fop.layout.FontInfo; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Bridge class for the <text> element. + * This bridge will use the direct text painter if the text + * for the element is simple. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @version $Id: PSTextElementBridge.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + */ +public class PSTextElementBridge extends SVGTextElementBridge { + + //private PSTextPainter textPainter; + + /** + * Constructs a new bridge for the <text> element. + * @param fi the font infomration + */ + public PSTextElementBridge(FontInfo fi) { + //textPainter = new PSTextPainter(fi); + } + + /** + * Create a text element bridge. + * This set the text painter on the node if the text is simple. + * @param ctx the bridge context + * @param e the svg element + * @return the text graphics node created by the super class + */ + public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { + GraphicsNode node = super.createGraphicsNode(ctx, e); + /* + if (node != null && isSimple(ctx, e, node)) { + ((TextNode)node).setTextPainter(getTextPainter()); + }*/ + return node; + } + + /* + private PSTextPainter getTextPainter() { + return textPainter; + } + */ + + /** + * Check if text element contains simple text. + * This checks the children of the text element to determine + * if the text is simple. The text is simple if it can be rendered + * with basic text drawing algorithms. This means there are no + * alternate characters, the font is known and there are no effects + * applied to the text. + * + * @param ctx the bridge context + * @param element the svg text element + * @param node the graphics node + * @return true if this text is simple of false if it cannot be + * easily rendered using normal drawString on the PDFGraphics2D + */ + private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) { + /* + // Font size, in user space units. + float fs = TextUtilities.convertFontSize(element).floatValue(); + // PDF cannot display fonts over 36pt + if (fs > 36) { + return false; + } + */ + + + for (Node n = element.getFirstChild(); + n != null; + n = n.getNextSibling()) { + + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + + if (n.getLocalName().equals(SVG_TSPAN_TAG) + || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) { + return false; + } else if (n.getLocalName().equals(SVG_TEXT_PATH_TAG)) { + return false; + } else if (n.getLocalName().equals(SVG_TREF_TAG)) { + return false; + } + break; + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + } + } + + /*if (CSSUtilities.convertFilter(element, node, ctx) != null) { + return false; + }*/ + + return true; + } +} + diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java new file mode 100644 index 000000000..6f2aab65a --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -0,0 +1,435 @@ +/* + * $Id$ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.awt.Graphics2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.Font; + +import java.text.AttributedCharacterIterator; +import java.awt.font.TextAttribute; +import java.awt.Shape; +import java.awt.Paint; +import java.awt.Stroke; +import java.awt.Color; +import java.util.List; +import java.util.Iterator; + +import org.apache.batik.gvt.text.Mark; +import org.apache.batik.gvt.TextPainter; +import org.apache.batik.gvt.TextNode; +import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; +import org.apache.batik.gvt.font.GVTFontFamily; +import org.apache.batik.bridge.SVGFontFamily; +import org.apache.batik.gvt.renderer.StrokingTextPainter; + +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.layout.FontState; +import org.apache.fop.layout.FontInfo; + +/** + * Renders the attributed character iterator of a <tt>TextNode</tt>. + * This class draws the text directly into the PSGraphics2D so that + * the text is not drawn using shapes which makes the PS files larger. + * If the text is simple enough to draw then it sets the font and calls + * drawString. If the text is complex or the cannot be translated + * into a simple drawString the StrokingTextPainter is used instead. + * + * @todo handle underline, overline and strikethrough + * @todo use drawString(AttributedCharacterIterator iterator...) for some + * + * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> + * @version $Id: PSTextPainter.java,v 1.15 2003/01/08 14:03:55 jeremias Exp $ + */ +public class PSTextPainter implements TextPainter { + private FontInfo fontInfo; + + /** + * Use the stroking text painter to get the bounds and shape. + * Also used as a fallback to draw the string with strokes. + */ + protected static final TextPainter PROXY_PAINTER = + StrokingTextPainter.getInstance(); + + /** + * Create a new PS text painter with the given font information. + * @param fi the fint info + */ + public PSTextPainter(FontInfo fi) { + fontInfo = fi; + } + + /** + * Paints the specified attributed character iterator using the + * specified Graphics2D and context and font context. + * @param node the TextNode to paint + * @param g2d the Graphics2D to use + */ + public void paint(TextNode node, Graphics2D g2d) { + // System.out.println("PSText paint"); + String txt = node.getText(); + Point2D loc = node.getLocation(); + + AttributedCharacterIterator aci = + node.getAttributedCharacterIterator(); + // reset position to start of char iterator + if (aci.getBeginIndex() == aci.getEndIndex()) { + return; + } + char ch = aci.first(); + if (ch == AttributedCharacterIterator.DONE) { + return; + } + TextNode.Anchor anchor; + anchor = (TextNode.Anchor) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE); + + List gvtFonts; + gvtFonts = (List) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES); + Paint forg = (Paint) aci.getAttribute(TextAttribute.FOREGROUND); + Paint strokePaint; + strokePaint = (Paint) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT); + Float size = (Float) aci.getAttribute(TextAttribute.SIZE); + if (size == null) { + return; + } + Stroke stroke = (Stroke) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.STROKE); + /* + Float xpos = (Float) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.X); + Float ypos = (Float) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.Y); + */ + + Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE); + Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT); + + boolean useStrokePainter = false; + + if (forg instanceof Color) { + Color col = (Color) forg; + if (col.getAlpha() != 255) { + useStrokePainter = true; + } + g2d.setColor(col); + } + g2d.setPaint(forg); + g2d.setStroke(stroke); + + if (strokePaint != null) { + // need to draw using AttributedCharacterIterator + useStrokePainter = true; + } + + if (hasUnsupportedAttributes(aci)) { + useStrokePainter = true; + } + + // text contains unsupported information + if (useStrokePainter) { + PROXY_PAINTER.paint(node, g2d); + return; + } + + String style = ((posture != null) && (posture.floatValue() > 0.0)) + ? "italic" : "normal"; + int weight = ((taWeight != null) + && (taWeight.floatValue() > 1.0)) ? FontInfo.BOLD + : FontInfo.NORMAL; + + FontState fontState = null; + FontInfo fi = fontInfo; + boolean found = false; + String fontFamily = null; + if (gvtFonts != null) { + Iterator i = gvtFonts.iterator(); + while (i.hasNext()) { + GVTFontFamily fam = (GVTFontFamily) i.next(); + if (fam instanceof SVGFontFamily) { + PROXY_PAINTER.paint(node, g2d); + return; + } + fontFamily = fam.getFamilyName(); + if (fi.hasFont(fontFamily, style, weight)) { + String fname = fontInfo.fontLookup(fontFamily, style, + weight); + FontMetrics metrics = fontInfo.getMetricsFor(fname); + int fsize = (int)(size.floatValue() * 1000); + fontState = new FontState(fname, metrics, fsize); + found = true; + break; + } + } + } + if (!found) { + String fname = + fontInfo.fontLookup("any", style, FontInfo.NORMAL); + FontMetrics metrics = fontInfo.getMetricsFor(fname); + int fsize = (int)(size.floatValue() * 1000); + fontState = new FontState(fname, metrics, fsize); + } else { + if (g2d instanceof PSGraphics2D) { + ((PSGraphics2D) g2d).setOverrideFontState(fontState); + } + } + int fStyle = Font.PLAIN; + if (weight == FontInfo.BOLD) { + if (style.equals("italic")) { + fStyle = Font.BOLD | Font.ITALIC; + } else { + fStyle = Font.BOLD; + } + } else { + if (style.equals("italic")) { + fStyle = Font.ITALIC; + } else { + fStyle = Font.PLAIN; + } + } + Font font = new Font(fontFamily, fStyle, + (int)(fontState.getFontSize() / 1000)); + + g2d.setFont(font); + + float advance = getStringWidth(txt, fontState); + float tx = 0; + if (anchor != null) { + switch (anchor.getType()) { + case TextNode.Anchor.ANCHOR_MIDDLE: + tx = -advance / 2; + break; + case TextNode.Anchor.ANCHOR_END: + tx = -advance; + } + } + g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY())); + } + + private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) { + boolean hasunsupported = false; + Object letSpace = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING); + if (letSpace != null) { + hasunsupported = true; + } + + Object wordSpace = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING); + if (wordSpace != null) { + hasunsupported = true; + } + + AttributedCharacterIterator.Attribute key; + key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE; + Object writeMod = aci.getAttribute(key); + if (!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals( + writeMod)) { + hasunsupported = true; + } + + Object vertOr = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION); + if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals( + vertOr)) { + hasunsupported = true; + } + return hasunsupported; + } + + private float getStringWidth(String str, FontState fontState) { + float wordWidth = 0; + float whitespaceWidth = fontState.getWidth(fontState.mapChar(' ')); + + for (int i = 0; i < str.length(); i++) { + float charWidth; + char c = str.charAt(i); + if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) { + charWidth = fontState.getWidth(fontState.mapChar(c)); + if (charWidth <= 0) { + charWidth = whitespaceWidth; + } + } else { + charWidth = whitespaceWidth; + } + wordWidth += charWidth; + } + return wordWidth / 1000f; + } + + /** + * Get the outline shape of the text characters. + * This uses the StrokingTextPainter to get the outline + * shape since in theory it should be the same. + * + * @param node the text node + * @return the outline shape of the text characters + */ + public Shape getOutline(TextNode node) { + return PROXY_PAINTER.getOutline(node); + } + + /** + * Get the bounds. + * This uses the StrokingTextPainter to get the bounds + * since in theory it should be the same. + * + * @param node the text node + * @return the bounds of the text + */ + public Rectangle2D getBounds2D(TextNode node) { + return PROXY_PAINTER.getBounds2D(node); + } + + /** + * Get the geometry bounds. + * This uses the StrokingTextPainter to get the bounds + * since in theory it should be the same. + * @param node the text node + * @return the bounds of the text + */ + public Rectangle2D getGeometryBounds(TextNode node) { + return PROXY_PAINTER.getGeometryBounds(node); + } + + // Methods that have no purpose for PS + + /** + * Get the mark. + * This does nothing since the output is pdf and not interactive. + * @param node the text node + * @param pos the position + * @param all select all + * @return null + */ + public Mark getMark(TextNode node, int pos, boolean all) { + System.out.println("PSText getMark"); + return null; + } + + /** + * Select at. + * This does nothing since the output is pdf and not interactive. + * @param x the x position + * @param y the y position + * @param node the text node + * @return null + */ + public Mark selectAt(double x, double y, TextNode node) { + System.out.println("PSText selectAt"); + return null; + } + + /** + * Select to. + * This does nothing since the output is pdf and not interactive. + * @param x the x position + * @param y the y position + * @param beginMark the start mark + * @return null + */ + public Mark selectTo(double x, double y, Mark beginMark) { + System.out.println("PSText selectTo"); + return null; + } + + /** + * Selec first. + * This does nothing since the output is pdf and not interactive. + * @param node the text node + * @return null + */ + public Mark selectFirst(TextNode node) { + System.out.println("PSText selectFirst"); + return null; + } + + /** + * Select last. + * This does nothing since the output is pdf and not interactive. + * @param node the text node + * @return null + */ + public Mark selectLast(TextNode node) { + System.out.println("PSText selectLast"); + return null; + } + + /** + * Get selected. + * This does nothing since the output is pdf and not interactive. + * @param start the start mark + * @param finish the finish mark + * @return null + */ + public int[] getSelected(Mark start, Mark finish) { + System.out.println("PSText getSelected"); + return null; + } + + /** + * Get the highlighted shape. + * This does nothing since the output is pdf and not interactive. + * @param beginMark the start mark + * @param endMark the end mark + * @return null + */ + public Shape getHighlightShape(Mark beginMark, Mark endMark) { + System.out.println("PSText getHighlightShape"); + return null; + } + +} + + diff --git a/src/java/org/apache/fop/render/ps/PSXMLHandler.java b/src/java/org/apache/fop/render/ps/PSXMLHandler.java new file mode 100644 index 000000000..3b4ddcdd1 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSXMLHandler.java @@ -0,0 +1,379 @@ +/* + * $Id: PSXMLHandler.java,v 1.4 2003/03/11 08:42:24 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +// Java +import java.awt.geom.AffineTransform; +import java.io.IOException; + +// DOM +import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGSVGElement; + +// Batik +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.ViewBox; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.gvt.TextPainter; + +// FOP +import org.apache.fop.render.XMLHandler; +import org.apache.fop.render.RendererContext; +import org.apache.fop.svg.SVGUserAgent; +import org.apache.fop.layout.FontInfo; + +/** + * PostScript XML handler. + * This handler handles XML for foreign objects when rendering to PostScript. + * It renders SVG to the PostScript document using the PSGraphics2D. + * The properties from the PostScript renderer are subject to change. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @version $Id: PSXMLHandler.java,v 1.4 2003/03/11 08:42:24 jeremias Exp $ + */ +public class PSXMLHandler implements XMLHandler { + + /** + * The PostScript generator that is being used to drawn into. + */ + public static final String PS_GENERATOR = "psGenerator"; + + /** + * The font information for the PostScript renderer. + */ + public static final String PS_FONT_INFO = "psFontInfo"; + + /** + * The width of the SVG graphic. + */ + public static final String PS_WIDTH = "width"; + + /** + * The height of the SVG graphic. + */ + public static final String PS_HEIGHT = "height"; + + /** + * The x position that this is being drawn at. + */ + public static final String PS_XPOS = "xpos"; + + /** + * The y position that this is being drawn at. + */ + public static final String PS_YPOS = "ypos"; + + /** + * Create a new PostScript XML handler for use by the PostScript renderer. + */ + public PSXMLHandler() { + } + + /** + * Handle the XML. + * This checks the type of XML and handles appropraitely. + * + * @param context the renderer context + * @param doc the XML document to render + * @param ns the namespace of the XML document + * @throws Exception any sort of exception could be thrown and shuld be handled + */ + public void handleXML(RendererContext context, Document doc, + String ns) throws Exception { + PSInfo psi = getPSInfo(context); + + String svg = "http://www.w3.org/2000/svg"; + if (svg.equals(ns)) { + SVGHandler svghandler = new SVGHandler(); + svghandler.renderSVGDocument(context, doc, psi); + } else { + } + } + + /** + * Get the pdf information from the render context. + * + * @param context the renderer context + * @return the pdf information retrieved from the context + */ + public static PSInfo getPSInfo(RendererContext context) { + PSInfo psi = new PSInfo(); + psi.psGenerator = (PSGenerator)context.getProperty(PS_GENERATOR); + psi.fontInfo = (FontInfo)context.getProperty(PS_FONT_INFO); + psi.width = ((Integer)context.getProperty(PS_WIDTH)).intValue(); + psi.height = ((Integer)context.getProperty(PS_HEIGHT)).intValue(); + psi.currentXPosition = ((Integer)context.getProperty(PS_XPOS)).intValue(); + psi.currentYPosition = ((Integer)context.getProperty(PS_YPOS)).intValue(); + return psi; + } + + /** + * PostScript information structure for drawing the XML document. + */ + public static class PSInfo { + + /** see PS_GENERATOR */ + private PSGenerator psGenerator; + /** see PS_FONT_INFO */ + private FontInfo fontInfo; + /** see PS_PAGE_WIDTH */ + private int width; + /** see PS_PAGE_HEIGHT */ + private int height; + /** see PS_XPOS */ + private int currentXPosition; + /** see PS_YPOS */ + private int currentYPosition; + /** + * Returns the PSGenerator. + * @return PSGenerator + */ + public PSGenerator getPSGenerator() { + return psGenerator; + } + + /** + * Sets the PSGenerator. + * @param psGenerator The PSGenerator to set + */ + public void setPsGenerator(PSGenerator psGenerator) { + this.psGenerator = psGenerator; + } + + /** + * Returns the fontInfo. + * @return FontInfo + */ + public FontInfo getFontInfo() { + return fontInfo; + } + + /** + * Sets the fontInfo. + * @param fontInfo The fontInfo to set + */ + public void setFontInfo(FontInfo fontInfo) { + this.fontInfo = fontInfo; + } + + /** + * Returns the currentXPosition. + * @return int + */ + public int getCurrentXPosition() { + return currentXPosition; + } + + /** + * Sets the currentXPosition. + * @param currentXPosition The currentXPosition to set + */ + public void setCurrentXPosition(int currentXPosition) { + this.currentXPosition = currentXPosition; + } + + /** + * Returns the currentYPosition. + * @return int + */ + public int getCurrentYPosition() { + return currentYPosition; + } + + /** + * Sets the currentYPosition. + * @param currentYPosition The currentYPosition to set + */ + public void setCurrentYPosition(int currentYPosition) { + this.currentYPosition = currentYPosition; + } + + /** + * Returns the width. + * @return int + */ + public int getWidth() { + return width; + } + + /** + * Sets the width. + * @param width The pageWidth to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * Returns the height. + * @return int + */ + public int getHeight() { + return height; + } + + /** + * Sets the height. + * @param height The height to set + */ + public void setHeight(int height) { + this.height = height; + } + + } + + /** + * This method is placed in an inner class so that we don't get class + * loading errors if batik is not present. + */ + protected class SVGHandler { + /** + * Render the svg document. + * @param context the renderer context + * @param doc the svg document + * @param psInfo the pdf information of the current context + */ + protected void renderSVGDocument(RendererContext context, Document doc, PSInfo psInfo) { + int xOffset = psInfo.currentXPosition; + int yOffset = psInfo.currentYPosition; + PSGenerator gen = psInfo.psGenerator; + + SVGUserAgent ua + = new SVGUserAgent(context.getUserAgent(), new AffineTransform()); + + + GVTBuilder builder = new GVTBuilder(); + BridgeContext ctx = new BridgeContext(ua); + PSTextElementBridge tBridge = new PSTextElementBridge(psInfo.getFontInfo()); + ctx.putBridge(tBridge); + + //PSAElementBridge aBridge = new PSAElementBridge(); + // to get the correct transform we need to use the PDFState + AffineTransform transform = gen.getCurrentState().getTransform(); + transform.translate(xOffset / 1000f, yOffset / 1000f); + //aBridge.setCurrentTransform(transform); + //ctx.putBridge(aBridge); + + TextPainter textPainter = new PSTextPainter(psInfo.getFontInfo()); + ctx.setTextPainter(textPainter); + GraphicsNode root; + try { + root = builder.build(ctx, doc); + } catch (Exception e) { + context.getUserAgent().getLogger().error("SVG graphic could not be built: " + + e.getMessage(), e); + return; + } + // get the 'width' and 'height' attributes of the SVG document + float w = (float)ctx.getDocumentSize().getWidth() * 1000f; + float h = (float)ctx.getDocumentSize().getHeight() * 1000f; + + float sx = psInfo.getWidth() / (float)w; + float sy = psInfo.getHeight() / (float)h; + + ctx = null; + builder = null; + + try { + gen.writeln("%SVG graphic start ---"); + /* + * Clip to the svg area. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ + gen.saveGraphicsState(); + // transform so that the coordinates (0,0) is from the top left + // and positive is down and to the right. (0,0) is where the + // viewBox puts it. + gen.concatMatrix(sx, 0, 0, sy, xOffset, yOffset); + + SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); + AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, + w / 1000f, h / 1000f); + if (!at.isIdentity()) { + double[] vals = new double[6]; + at.getMatrix(vals); + gen.concatMatrix(vals); + } + + /* + if (psInfo.pdfContext == null) { + psInfo.pdfContext = psInfo.pdfPage; + }*/ + PSGraphics2D graphics = new PSGraphics2D(true, gen); + graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); + //psInfo.pdfState.push(); + transform = new AffineTransform(); + // scale to viewbox + transform.translate(xOffset, yOffset); + gen.getCurrentState().concatMatrix(transform); + //graphics.setPDFState(psInfo.pdfState); + try { + root.paint(graphics); + //psInfo.currentStream.add(graphics.getString()); + } catch (Exception e) { + context.getUserAgent().getLogger().error("SVG graphic could not be rendered: " + + e.getMessage(), e); + } + + psInfo.psGenerator.restoreGraphicsState(); + //psInfo.pdfState.pop(); + gen.writeln("%SVG graphic end ---"); + } catch (IOException ioe) { + context.getUserAgent().getLogger().error("SVG graphic could not be rendered: " + + ioe.getMessage(), ioe); + } + } + } +} + diff --git a/src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java b/src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java new file mode 100644 index 000000000..bdad9c0f0 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java @@ -0,0 +1,217 @@ +/* + * $Id: RunLengthEncodeOutputStream.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.render.ps; + +import java.io.FilterOutputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * This class applies a RunLengthEncode filter to the stream. + * + * @author <a href="mailto:smwolke@geistig.com">Stephen Wolke</a> + * @version $Id: RunLengthEncodeOutputStream.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $ + */ +public class RunLengthEncodeOutputStream extends FilterOutputStream + implements Finalizable { + + private static final int MAX_SEQUENCE_COUNT = 127; + private static final int END_OF_DATA = 128; + private static final int BYTE_MAX = 256; + + private static final int NOT_IDENTIFY_SEQUENCE = 0; + private static final int START_SEQUENCE = 1; + private static final int IN_SEQUENCE = 2; + private static final int NOT_IN_SEQUENCE = 3; + + private int runCount = 0; + private int isSequence = NOT_IDENTIFY_SEQUENCE; + private byte[] runBuffer = new byte[MAX_SEQUENCE_COUNT + 1]; + + + /** @see java.io.FilterOutputStream **/ + public RunLengthEncodeOutputStream(OutputStream out) { + super(out); + } + + + /** @see java.io.FilterOutputStream **/ + public void write(byte b) + throws java.io.IOException { + runBuffer[runCount] = b; + + switch (runCount) { + case 0: + runCount = 0; + isSequence = NOT_IDENTIFY_SEQUENCE; + runCount++; + break; + case 1: + if (runBuffer[runCount] != runBuffer[runCount - 1]) { + isSequence = NOT_IN_SEQUENCE; + } + runCount++; + break; + case 2: + if (runBuffer[runCount] != runBuffer[runCount - 1]) { + isSequence = NOT_IN_SEQUENCE; + } else { + if (isSequence == NOT_IN_SEQUENCE) { + isSequence = START_SEQUENCE; + } else { + isSequence = IN_SEQUENCE; + } + } + runCount++; + break; + case MAX_SEQUENCE_COUNT: + if (isSequence == IN_SEQUENCE) { + out.write(BYTE_MAX - (MAX_SEQUENCE_COUNT - 1)); + out.write(runBuffer[runCount - 1]); + runBuffer[0] = runBuffer[runCount]; + runCount = 1; + } else { + out.write(MAX_SEQUENCE_COUNT); + out.write(runBuffer, 0, runCount + 1); + runCount = 0; + } + isSequence = NOT_IDENTIFY_SEQUENCE; + break; + default: + switch (isSequence) { + case IN_SEQUENCE: + if (runBuffer[runCount] != runBuffer[runCount - 1]) { + out.write(BYTE_MAX - (runCount - 1)); + out.write(runBuffer[runCount - 1]); + runBuffer[0] = runBuffer[runCount]; + runCount = 1; + isSequence = NOT_IDENTIFY_SEQUENCE; + break; + } + runCount++; + break; + case NOT_IN_SEQUENCE: + if (runBuffer[runCount] == runBuffer[runCount - 1]) { + isSequence = START_SEQUENCE; + } + runCount++; + break; + case START_SEQUENCE: + if (runBuffer[runCount] == runBuffer[runCount - 1]) { + out.write(runCount - 3); + out.write(runBuffer, 0, runCount - 2); + runBuffer[0] = runBuffer[runCount]; + runBuffer[1] = runBuffer[runCount]; + runBuffer[2] = runBuffer[runCount]; + runCount = 3; + isSequence = IN_SEQUENCE; + break; + } else { + isSequence = NOT_IN_SEQUENCE; + runCount++; + break; + } + } + } + } + + + /** @see java.io.FilterOutputStream **/ + public void write(byte[] b) + throws IOException { + + for (int i = 0; i < b.length; i++) { + this.write(b[i]); + } + } + + + /** @see java.io.FilterOutputStream **/ + public void write(byte[] b, int off, int len) + throws IOException { + + for (int i = 0; i < len; i++) { + this.write(b[off + i]); + } + } + + + /** @see org.apache.fop.render.ps.Finalizable **/ + public void finalizeStream() + throws IOException { + switch (isSequence) { + case IN_SEQUENCE: + out.write(BYTE_MAX - (runCount - 1)); + out.write(runBuffer[runCount - 1]); + break; + default: + out.write(runCount - 1); + out.write(runBuffer, 0, runCount); + } + + out.write(END_OF_DATA); + + flush(); + if (out instanceof Finalizable) { + ((Finalizable) out).finalizeStream(); + } + } + + + /** @see java.io.FilterOutputStream **/ + public void close() + throws IOException { + finalizeStream(); + super.close(); + } + +} + |