<?xml version="1.0" standalone="yes" ?>
<property-list family="FO">
<generic-property-list>
- <property type="generic">
- <name>generic-color</name>
- <class-name>GenericColor</class-name>
- <datatype>ColorType</datatype>
- <extfile href="colorkw.xml"/>
+ <property type="generic">
+ <name>generic-color</name>
+ <class-name>GenericColor</class-name>
+ <datatype>ColorType</datatype>
+ <extfile href="colorkw.xml"/>
<!--
- <datatype-conversion from-type="String" varname="strval">
- new ColorType(strval)</datatype-conversion>
+ <datatype-conversion from-type="String" varname="strval">
+ new ColorType(strval)</datatype-conversion>
-->
- </property>
- <property type="generic">
- <name>generic-boolean</name>
- <class-name>GenericBoolean</class-name>
- <datatype>Enum</datatype>
- <enumeration>
- <value const="TRUE">true</value>
- <value const="FALSE">false</value>
- </enumeration>
- </property>
- <property type="generic">
- <name>generic-keep</name>
- <class-name>GenericKeep</class-name>
- <datatype>Keep</datatype> <!-- CompoundDatatype -->
- <compound>
- <subproperty set-by-shorthand="true">
- <name>within-page</name>
- <datatype>Number</datatype>
- <default>auto</default>
- <enumeration>
- <value const="AUTO">auto</value>
- <value const="ALWAYS">always</value>
- </enumeration>
- </subproperty>
- <subproperty set-by-shorthand="true">
- <name>within-line</name>
- <datatype>Number</datatype>
- <default>auto</default>
- <enumeration>
- <value const="AUTO">auto</value>
- <value const="ALWAYS">always</value>
- </enumeration>
- </subproperty>
- <subproperty set-by-shorthand="true">
- <name>within-column</name>
- <datatype>Number</datatype>
- <default>auto</default>
- <enumeration>
- <value const="AUTO">auto</value>
- <value const="ALWAYS">always</value>
- </enumeration>
- </subproperty>
- </compound>
- </property>
- <property type="generic">
- <name>conditional-length-template</name>
- <class-name>GenericCondLength</class-name>
- <datatype>CondLength</datatype>
- <compound>
- <subproperty set-by-shorthand="true">
- <name>length</name>
- <datatype>Length</datatype>
- </subproperty>
- <subproperty>
- <name>conditionality</name>
- <datatype>Enum</datatype>
- <enumeration>
- <value const="DISCARD">discard</value>
- <value const="RETAIN">retain</value>
- </enumeration>
- </subproperty>
- </compound>
- </property>
- <property type="generic">
- <name>padding-template</name>
- <class-name>GenericCondPadding</class-name>
- <use-generic>GenericCondLength</use-generic>
- <inherited>false</inherited>
- <default subproperty="length">0pt</default>
- </property>
- <property type="generic">
- <name>padding-template</name>
- <class-name>GenericPadding</class-name>
- <datatype>Length</datatype>
- <inherited>false</inherited>
- <default>0pt</default>
+ </property>
+ <property type="generic">
+ <name>generic-boolean</name>
+ <class-name>GenericBoolean</class-name>
+ <datatype>Enum</datatype>
+ <enumeration>
+ <value const="TRUE">true</value>
+ <value const="FALSE">false</value>
+ </enumeration>
+ </property>
+ <property type="generic">
+ <name>generic-keep</name>
+ <class-name>GenericKeep</class-name>
+ <datatype>Keep</datatype> <!-- CompoundDatatype -->
+ <compound>
+ <subproperty set-by-shorthand="true">
+ <name>within-page</name>
+ <datatype>Number</datatype>
+ <default>auto</default>
+ <enumeration>
+ <value const="AUTO">auto</value>
+ <value const="ALWAYS">always</value>
+ </enumeration>
+ </subproperty>
+ <subproperty set-by-shorthand="true">
+ <name>within-line</name>
+ <datatype>Number</datatype>
+ <default>auto</default>
+ <enumeration>
+ <value const="AUTO">auto</value>
+ <value const="ALWAYS">always</value>
+ </enumeration>
+ </subproperty>
+ <subproperty set-by-shorthand="true">
+ <name>within-column</name>
+ <datatype>Number</datatype>
+ <default>auto</default>
+ <enumeration>
+ <value const="AUTO">auto</value>
+ <value const="ALWAYS">always</value>
+ </enumeration>
+ </subproperty>
+ </compound>
+ </property>
+ <property type="generic">
+ <name>conditional-length-template</name>
+ <class-name>GenericCondLength</class-name>
+ <datatype>CondLength</datatype>
+ <compound>
+ <subproperty set-by-shorthand="true">
+ <name>length</name>
+ <datatype>Length</datatype>
+ </subproperty>
+ <subproperty>
+ <name>conditionality</name>
+ <datatype>Enum</datatype>
+ <enumeration>
+ <value const="DISCARD">discard</value>
+ <value const="RETAIN">retain</value>
+ </enumeration>
+ </subproperty>
+ </compound>
+ </property>
+ <property type="generic">
+ <name>padding-template</name>
+ <class-name>GenericCondPadding</class-name>
+ <use-generic>GenericCondLength</use-generic>
+ <inherited>false</inherited>
+ <default subproperty="length">0pt</default>
+ </property>
+ <property type="generic">
+ <name>padding-template</name>
+ <class-name>GenericPadding</class-name>
+ <datatype>Length</datatype>
+ <inherited>false</inherited>
+ <default>0pt</default>
<shorthand>padding</shorthand>
- </property>
+ </property>
<!-- Before, After, Start, End border width props -->
<!-- CondLength, but adds keyword values both to the "shorthand" setting
- and to the length component. So we redefine the components here,
- rather than doing a "use-generic" on GenericCondLength.
+ and to the length component. So we redefine the components here,
+ rather than doing a "use-generic" on GenericCondLength.
-->
- <property type="generic">
- <name>border-cond-width-template</name>
- <class-name>GenericCondBorderWidth</class-name>
- <keyword-equiv match="thin">0.5pt</keyword-equiv>
- <keyword-equiv match="medium">1pt</keyword-equiv>
- <keyword-equiv match="thick">2pt</keyword-equiv>
- <inherited>false</inherited>
- <datatype>CondLength</datatype>
- <compound>
- <subproperty set-by-shorthand="true">
- <name>length</name>
- <datatype>Length</datatype>
- <keyword-equiv match="thin">0.5pt</keyword-equiv>
- <keyword-equiv match="medium">1pt</keyword-equiv>
- <keyword-equiv match="thick">2pt</keyword-equiv>
- <default>medium</default>
- </subproperty>
- <subproperty>
- <datatype>Enum</datatype>
- <name>conditionality</name>
- <enumeration>
- <value const="DISCARD">discard</value>
- <value const="RETAIN">retain</value>
- </enumeration>
- </subproperty>
- </compound>
- </property>
+ <property type="generic">
+ <name>border-cond-width-template</name>
+ <class-name>GenericCondBorderWidth</class-name>
+ <keyword-equiv match="thin">0.5pt</keyword-equiv>
+ <keyword-equiv match="medium">1pt</keyword-equiv>
+ <keyword-equiv match="thick">2pt</keyword-equiv>
+ <inherited>false</inherited>
+ <datatype>CondLength</datatype>
+ <compound>
+ <subproperty set-by-shorthand="true">
+ <name>length</name>
+ <datatype>Length</datatype>
+ <keyword-equiv match="thin">0.5pt</keyword-equiv>
+ <keyword-equiv match="medium">1pt</keyword-equiv>
+ <keyword-equiv match="thick">2pt</keyword-equiv>
+ <default>medium</default>
+ </subproperty>
+ <subproperty>
+ <datatype>Enum</datatype>
+ <name>conditionality</name>
+ <enumeration>
+ <value const="DISCARD">discard</value>
+ <value const="RETAIN">retain</value>
+ </enumeration>
+ </subproperty>
+ </compound>
+ </property>
<!-- Left, Right, Top, Bottom borderwidth props -->
- <property type="generic">
- <name>border-width-template</name>
- <class-name>GenericBorderWidth</class-name>
- <datatype>Length</datatype>
- <keyword-equiv match="thin">0.5pt</keyword-equiv>
- <keyword-equiv match="medium">1pt</keyword-equiv>
- <keyword-equiv match="thick">2pt</keyword-equiv>
- <inherited>false</inherited>
- <default>0pt</default>
- <shorthand>border-width</shorthand>
- </property>
- <property type="generic">
- <name>border-style-template</name>
- <class-name>GenericBorderStyle</class-name>
- <inherited>false</inherited>
- <datatype>Enum</datatype>
- <enumeration>
- <value const="NONE">none</value>
- <value const="HIDDEN">hidden</value>
- <value const="DOTTED">dotted</value>
- <value const="DASHED">dashed</value>
- <value const="SOLID">solid</value>
- <value const="DOUBLE">double</value>
- <value const="GROOVE">groove</value>
- <value const="RIDGE">ridge</value>
- <value const="INSET">inset</value>
- <value const="OUTSET">outset</value>
- </enumeration>
- <default>none</default>
- <shorthand>border-style</shorthand>
- </property>
- <property type="generic">
- <name>break-template</name>
- <class-name>GenericBreak</class-name>
- <inherited>false</inherited>
- <datatype>Enum</datatype>
- <enumeration>
- <value const="AUTO">auto</value>
- <value const="COLUMN">column</value>
- <value const="PAGE">page</value>
- <value const="EVEN_PAGE">even-page</value>
- <value const="ODD_PAGE">odd-page</value>
- </enumeration>
- <default>auto</default>
- </property>
- <property type="generic">
- <name>generic-space</name>
- <class-name>GenericSpace</class-name>
- <inherited>false</inherited>
- <datatype>Space</datatype>
- <compound>
- <subproperty set-by-shorthand="true">
- <name>minimum</name>
- <datatype>Length</datatype>
- <default>0pt</default>
- </subproperty>
- <subproperty set-by-shorthand="true">
- <name>optimum</name>
- <datatype>Length</datatype>
- <default>0pt</default>
- </subproperty>
- <subproperty set-by-shorthand="true">
- <name>maximum</name>
- <datatype>Length</datatype>
- <default>0pt</default>
- </subproperty>
- <subproperty>
- <name>precedence</name>
- <datatype>Number</datatype>
- <enumeration>
- <value const="FORCE">force</value>
- </enumeration>
- <default>0</default>
- </subproperty>
- <subproperty>
- <name>conditionality</name>
- <datatype>Enum</datatype>
- <enumeration>
- <value const="DISCARD">discard</value>
- <value const="RETAIN">retain</value>
- </enumeration>
- <default>discard</default>
- </subproperty>
- </compound>
- </property>
+ <property type="generic">
+ <name>border-width-template</name>
+ <class-name>GenericBorderWidth</class-name>
+ <datatype>Length</datatype>
+ <keyword-equiv match="thin">0.5pt</keyword-equiv>
+ <keyword-equiv match="medium">1pt</keyword-equiv>
+ <keyword-equiv match="thick">2pt</keyword-equiv>
+ <inherited>false</inherited>
+ <default>0pt</default>
+ <shorthand>border-width</shorthand>
+ </property>
+ <property type="generic">
+ <name>border-style-template</name>
+ <class-name>GenericBorderStyle</class-name>
+ <inherited>false</inherited>
+ <datatype>Enum</datatype>
+ <enumeration>
+ <value const="NONE">none</value>
+ <value const="HIDDEN">hidden</value>
+ <value const="DOTTED">dotted</value>
+ <value const="DASHED">dashed</value>
+ <value const="SOLID">solid</value>
+ <value const="DOUBLE">double</value>
+ <value const="GROOVE">groove</value>
+ <value const="RIDGE">ridge</value>
+ <value const="INSET">inset</value>
+ <value const="OUTSET">outset</value>
+ </enumeration>
+ <default>none</default>
+ <shorthand>border-style</shorthand>
+ </property>
+ <property type="generic">
+ <name>break-template</name>
+ <class-name>GenericBreak</class-name>
+ <inherited>false</inherited>
+ <datatype>Enum</datatype>
+ <enumeration>
+ <value const="AUTO">auto</value>
+ <value const="COLUMN">column</value>
+ <value const="PAGE">page</value>
+ <value const="EVEN_PAGE">even-page</value>
+ <value const="ODD_PAGE">odd-page</value>
+ </enumeration>
+ <default>auto</default>
+ </property>
+ <property type="generic">
+ <name>generic-space</name>
+ <class-name>GenericSpace</class-name>
+ <inherited>false</inherited>
+ <datatype>Space</datatype>
+ <compound>
+ <subproperty set-by-shorthand="true">
+ <name>minimum</name>
+ <datatype>Length</datatype>
+ <default>0pt</default>
+ </subproperty>
+ <subproperty set-by-shorthand="true">
+ <name>optimum</name>
+ <datatype>Length</datatype>
+ <default>0pt</default>
+ </subproperty>
+ <subproperty set-by-shorthand="true">
+ <name>maximum</name>
+ <datatype>Length</datatype>
+ <default>0pt</default>
+ </subproperty>
+ <subproperty>
+ <name>precedence</name>
+ <datatype>Number</datatype>
+ <enumeration>
+ <value const="FORCE">force</value>
+ </enumeration>
+ <default>0</default>
+ </subproperty>
+ <subproperty>
+ <name>conditionality</name>
+ <datatype>Enum</datatype>
+ <enumeration>
+ <value const="DISCARD">discard</value>
+ <value const="RETAIN">retain</value>
+ </enumeration>
+ <default>discard</default>
+ </subproperty>
+ </compound>
+ </property>
<!-- Common Accessibility Properties -->
<property>
<name>letter-spacing</name>
<inherited>true</inherited>
- <datatype>ToBeImplemented</datatype>
- <default>normal</default>
+ <datatype>Length</datatype>
+ <default>0pt</default>
</property>
<property>
<name>suppress-at-line-break</name>
package org.apache.fop.datatypes;
public class ColorSpace {
+ private boolean hasICCProfile;
+ private byte[] iccProfile;
+ private int numComponents;
+
// Ok... so I had some grand purpose for this, but I can't recall.
// I'm just writing it
public static int DEVICE_RGB = 2;
public static int DEVICE_CMYK = 3;
+
// Are there any others?
protected int currentColorSpace = -1;
public ColorSpace(int theColorSpace) {
this.currentColorSpace = theColorSpace;
+ hasICCProfile = false;
+ numComponents = calculateNumComponents();
+ }
+
+ private int calculateNumComponents() {
+ if (currentColorSpace == DEVICE_GRAY)
+ return 1;
+ else if (currentColorSpace == DEVICE_RGB)
+ return 3;
+ else if (currentColorSpace == DEVICE_CMYK)
+ return 4;
+ else
+ return 0;
+ }
+ public void setColorSpace(int theColorSpace) {
+ this.currentColorSpace = theColorSpace;
+ numComponents = calculateNumComponents();
+ }
+
+ public boolean hasICCProfile() {
+ return hasICCProfile;
+ }
+
+ public byte[] getICCProfile() {
+ if (hasICCProfile)
+ return iccProfile;
+ else
+ return new byte[0];
+ }
+
+ public void setICCProfile(byte[] iccProfile) {
+ this.iccProfile = iccProfile;
+ hasICCProfile = true;
}
public int getColorSpace() {
return (this.currentColorSpace);
}
- public void setColorSpace(int theColorSpace) {
- this.currentColorSpace = theColorSpace;
+ public int getNumComponents() {
+ return numComponents;
}
public String getColorSpacePDFString() { // this is for PDF Output. Does anyone else need a string representation?
int fontVariant =
this.parent.properties.get("font-variant").getEnum();
+ int letterSpacing =
+ this.parent.properties.get("letter-spacing").getLength().mvalue();
this.fs = new FontState(area.getFontInfo(), fontFamily,
fontStyle, fontWeight, fontSize,
- fontVariant);
+ fontVariant, letterSpacing);
ColorType c = this.parent.properties.get("color").getColorType();
this.red = c.red();
mtx_tab[i] = new TTFMtxEntry();
for (int i = 0; i < nhmtx; i++) {
mtx_tab[i].wx = in.readTTFUShort();
- mtx_tab[i].lsb = in.readTTFUShort();
+ mtx_tab[i].lsb = in.readTTFShort();
/*
* System.out.println(" width["+i+"] = "+
* get_ttf_funit(mtx_tab[i].wx)+";");
int lastWidth = mtx_tab[nhmtx - 1].wx;
for (int i = nhmtx; i < mtx_size; i++) {
mtx_tab[i].wx = lastWidth;
- mtx_tab[i].lsb = in.readTTFUShort();
+ mtx_tab[i].lsb = in.readTTFShort();
}
}
}
*/
public abstract class AbstractFopImage implements FopImage {
+ /**
+ * Photoshop generated cmykl jpeg's are inverted.
+ */
+ protected boolean m_invertImage = false;
+
/**
* Image width (in pixel).
*/
*/
abstract protected void loadImage() throws FopImageException;
+ /**
+ * If true, image data are inverted
+ */
+ public boolean invertImage() {
+ return m_invertImage;
+ }
+
/**
* Return the image URL.
* @return the image URL (as String)
// FOP
import org.apache.fop.apps.Driver;
+import org.apache.fop.messaging.*;
import org.apache.fop.datatypes.ColorSpace;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.image.analyser.ImageReader;
public class EPSImage extends AbstractFopImage {
private String docName;
private int[] bbox;
-
+
private byte[] epsImage = null;
private EPSReader epsReader = null;
-
- /**
- * Initialize docName and bounding box
- */
+
+ /**
+ * Initialize docName and bounding box
+ */
private void init(URL href) {
bbox = new int[4];
bbox[0] = 0;
bbox[1] = 0;
bbox[2] = 0;
bbox[3] = 0;
-
+
docName = href.toString();
}
-
- /**
- * Return the name of the eps
- */
+
+ /**
+ * Return the name of the eps
+ */
public String getDocName() {
return docName;
}
-
- /**
- * Return the bounding box
- */
+
+ /**
+ * Return the bounding box
+ */
public int[] getBBox() {
return bbox;
}
-
+
public EPSImage(URL href) throws FopImageException {
super(href);
init(href);
}
-
+
public EPSImage(URL href,
ImageReader imgReader) throws FopImageException {
super(href, imgReader);
bbox = eimgReader.getBBox();
}
}
-
+
protected void loadImage() throws FopImageException {
- // Image is loaded in reader
+ // Image is loaded in reader
}
-
+
public byte[] getEPSImage() throws FopImageException {
- if (epsImage == null) {
- //log.error("ERROR LOADING EXTERNAL EPS");
- }
+ if (epsImage == null)
+ MessageHandler.errorln("ERROR LOADING EXTERNAL EPS");
return epsImage;
}
-
+
}
// Methods throw exception because they can retrieve data
// when needed.
- // Ressource location
+ public boolean invertImage();
+
+ // Resource location
public String getURL();
// image size
// maybe relative
URL context_url = null;
String base = Configuration.getStringValue("baseDir");
+
if(base == null) {
throw new FopImageException("Error with image URL: "
+ e.getMessage()
+ " and no base directory is specified");
}
+
try {
absoluteURL = new URL(Configuration.getStringValue("baseDir")
+ absoluteURL.getFile());
} else if ("image/tga".equals(imgMimeType)) {
imgClassName = "org.apache.fop.image.JimiImage";
// imgClassName = "org.apache.fop.image.JAIImage";
+ } else if ("image/eps".equals(imgMimeType)) {
+ imgClassName = "org.apache.fop.image.EPSImage";
} else if ("image/tiff".equals(imgMimeType)) {
imgClassName = "org.apache.fop.image.JimiImage";
// imgClassName = "org.apache.fop.image.JAIImage";
* @see FopImage
*/
public class JpegImage extends AbstractFopImage {
+ boolean hasAPPEMarker = false;
+ boolean found_icc_profile = false;
+ boolean found_dimensions = false;
+
public JpegImage(URL href) throws FopImageException {
super(href);
}
protected void loadImage() throws FopImageException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ByteArrayOutputStream iccStream = new ByteArrayOutputStream();
InputStream inStream;
-
+ this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_UNKNOWN);
byte[] readBuf = new byte[4096];
int bytes_read;
int index = 0;
this.m_bitmaps[index + 8]);
if (this.m_bitmaps[index + 9] == 1) {
- this.m_colorSpace = new ColorSpace(
- ColorSpace.DEVICE_GRAY);
+ this.m_colorSpace.setColorSpace(ColorSpace.DEVICE_GRAY);
} else if (this.m_bitmaps[index + 9] == 3) {
- this.m_colorSpace =
- new ColorSpace(ColorSpace.DEVICE_RGB);
- } else {
+ this.m_colorSpace.setColorSpace(ColorSpace.DEVICE_RGB);
+ } else if (this.m_bitmaps[index + 9] == 4) {
+ this.m_colorSpace.setColorSpace(ColorSpace.DEVICE_CMYK);
+ }
+
+ found_dimensions = true;
+ if (found_icc_profile) {
cont = false;
- throw new FopImageException(
- "\n2 Error while loading image " +
- this.m_href.toString() +
- " : JpegImage - Invalid JPEG Header (bad color space " +
- this.m_bitmaps[index + 9] + ").");
+ break;
+ }
+ index += calcBytes(this.m_bitmaps[index + 2],
+ this.m_bitmaps[index + 3]) + 2;
+
+ } else if (uByte(this.m_bitmaps[index+1]) == 226 &&
+ this.m_bitmaps.length > (index+60)) {
+ // Check if ICC profile
+ byte[] icc_string = new byte[11];
+ System.arraycopy(this.m_bitmaps, index+4, icc_string, 0, 11);
+
+ /*
+ byte[] acsp = new byte[4];
+ System.arraycopy(this.m_bitmaps, index+18+36, acsp, 0, 4);
+ boolean first_chunk = false;
+ if ("acsp".equals(new String(acsp))) {
+ System.out.println("1st icc chunk");
+ first_chunk = true;
}
+ */
+ if ("ICC_PROFILE".equals(new String(icc_string))){
+ int chunkSize = calcBytes(this.m_bitmaps[index + 2],
+ this.m_bitmaps[index + 3]) + 2;
- cont = false;
- break;
+ if (iccStream.size() == 0)
+ iccStream.write(this.m_bitmaps, index+18, chunkSize - 20);
+ else
+ iccStream.write(this.m_bitmaps, index+16, chunkSize - 18); // eller 18..
+
+ }
- } else { // if (uByte(this.m_bitmaps[index + 1]) == headers[headerIndex]) {
+ index += calcBytes(this.m_bitmaps[index + 2],
+ this.m_bitmaps[index + 3]) + 2;
+ // Check for Adobe APPE Marker
+ } else if ((uByte(this.m_bitmaps[index]) == 0xff &&
+ uByte(this.m_bitmaps[index+1]) == 0xee &&
+ uByte(this.m_bitmaps[index+2]) == 0 &&
+ uByte(this.m_bitmaps[index+3]) == 14 &&
+ "Adobe".equals(new String(this.m_bitmaps, index+4, 5)))) {
+ // The reason for reading the APPE marker is that photoshop
+ // generates cmyk jpeg's with inverted values. The correct thing
+ // to do would be to interpret the values in the marker, but for now
+ // only assume that if APPE marker is present and colorspace is CMYK,
+ // the image is inverted.
+ hasAPPEMarker = true;
+
+ index += calcBytes(this.m_bitmaps[index + 2],
+ this.m_bitmaps[index + 3]) + 2;
+ } else {
index += calcBytes(this.m_bitmaps[index + 2],
this.m_bitmaps[index + 3]) + 2;
}
+
} else {
cont = false;
+ /*
throw new FopImageException(
"\n2 Error while loading image " +
this.m_href.toString() + " : JpegImage - Invalid JPEG Header (bad header byte).");
+ */
}
}
} else {
throw new FopImageException( "\n1 Error while loading image " +
this.m_href.toString() + " : JpegImage - Invalid JPEG Header.");
}
+ if (iccStream.size() > 0) {
+ byte[] align = new byte[((iccStream.size()) % 8) + 8];
+ try {iccStream.write(align);} catch (Exception e) {
+ throw new FopImageException( "\n1 Error while loading image " +
+ this.m_href.toString() + " : " + e.getMessage());
+ }
+ this.m_colorSpace.setICCProfile(iccStream.toByteArray());
+ }
+
+ if (hasAPPEMarker && this.m_colorSpace.getColorSpace() == ColorSpace.DEVICE_CMYK)
+ this.m_invertImage = true;
}
private int calcBytes(byte bOne, byte bTwo) {
import java.io.InputStream;
import java.net.URL;
+
+// FOP
+import org.apache.fop.messaging.*;
+import org.apache.fop.image.SVGImage;
+
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
+
/**
- * ImageReader object for EPS document image type.
+ * ImageReader object for SVG document image type.
*/
public class EPSReader extends AbstractImageReader {
private long[] bbox;
private boolean isAscii; // True if plain ascii eps file
-
- // offsets if not ascii
+
+ // offsets if not ascii
long psStart = 0;
long psLength = 0;
long wmfStart = 0;
long wmfLength = 0;
long tiffStart = 0;
long tiffLength = 0;
-
- /** raw eps file */
+
+ /** raw eps file */
private byte[] rawEps;
- /** eps part */
+ /** eps part */
private byte[] epsFile;
private byte[] preview = null;
-
+
private long getLong(byte[] buf, int idx) {
int b1 = buf[idx] & 0xff;
int b2 = buf[idx+1] & 0xff;
int b3 = buf[idx+2] & 0xff;
int b4 = buf[idx+3] & 0xff;
-
+
+ //return (long)((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
return (long)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
}
-
+
public boolean verifySignature(String uri, BufferedInputStream fis)
- throws IOException {
+ throws IOException {
boolean isEPS = false;
this.imageStream = fis;
fis.mark(32);
byte[] header = new byte[30];
fis.read(header, 0, 30);
fis.reset();
-
- // Check if binary header
+
+ // Check if binary header
+ //if (getLong(header, 0) == 0xC5D0D3C6) {
if (getLong(header, 0) == 0xC6D3D0C5) {
isAscii = false;
isEPS = true;
-
+
psStart = getLong(header, 4);
psLength = getLong(header, 8);
wmfStart = getLong(header, 12);
wmfLength = getLong(header, 16);
tiffStart = getLong(header, 20);
tiffLength = getLong(header, 24);
-
+
} else {
- // Check if plain ascii
+ // Check if plain ascii
byte[] epsh = "%!PS".getBytes();
if (epsh[0] == header[0] &&
epsh[1] == header[1] &&
isEPS = true;
}
}
-
+
if (isEPS) {
readEPSImage(fis);
bbox = readBBox();
-
+
if (bbox != null) {
width = (int)(bbox[2]-bbox[0]);
height = (int)(bbox[3]-bbox[1]);
} else {
- // Ain't eps if no BoundingBox
+ // Ain't eps if no BoundingBox
isEPS = false;
}
}
-
+
return isEPS;
}
-
- /** read the eps file and extract eps part */
+
+ /** read the eps file and extract eps part */
private void readEPSImage(BufferedInputStream fis) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] file;
int bytes_read;
int index = 0;
boolean cont = true;
-
-
+
+
try {
while ((bytes_read = fis.read(readBuf)) != -1) {
baos.write(readBuf, 0, bytes_read);
} catch (java.io.IOException ex) {
throw new IOException("Error while loading EPS image " + ex.getMessage());
}
-
+
file = baos.toByteArray();
-
+
if (isAscii) {
rawEps = null;
epsFile = new byte[file.length];
System.arraycopy(rawEps, (int)psStart, epsFile, 0, (int)psLength);
}
}
-
+
public byte[] getEpsFile() {
return epsFile;
}
-
- /* Get embedded preview or null */
+
+ /* Get embedded preview or null */
public byte[] getPreview() {
InputStream is = null;
if (preview == null) {
}
return preview;
}
-
- /** Extract bounding box from eps part
- */
+
+ /** Extract bounding box from eps part
+ */
private long[] readBBox() {
long[] mbbox = null;
int idx = 0;
byte[] bbxName = "%%BoundingBox: ".getBytes();
boolean found = false;
-
+
while (!found && (epsFile.length > (idx + bbxName.length))) {
boolean sfound = true;
int i = idx;
idx++;
}
}
-
+
if (!found)
return mbbox;
-
-
+
+
mbbox = new long[4];
idx += readLongString(mbbox, 0, idx);
idx += readLongString(mbbox, 1, idx);
idx += readLongString(mbbox, 2, idx);
idx += readLongString(mbbox, 3, idx);
-
+
return mbbox;
}
-
+
private int readLongString(long[] mbbox, int i, int idx) {
while (idx < epsFile.length &&
(epsFile[idx] == 32))
- idx++;
-
+ idx++;
+
int nidx = idx;
-
+
while (nidx < epsFile.length &&
- (epsFile[nidx] >= 48 && epsFile[nidx] <= 57))
+ (epsFile[nidx] >= 48 && epsFile[nidx] <= 57))
nidx++;
-
+
byte[] num = new byte[nidx - idx];
System.arraycopy(epsFile, idx, num, 0, nidx-idx);
String ns = new String(num);
mbbox[i] = Long.parseLong(ns);
-
+
return (1+nidx - idx);
}
-
+
public String getMimeType() {
return "image/eps";
}
-
- /**
- * Return the BoundingBox
- */
+
+ /**
+ * Return the BoundingBox
+ */
public int[] getBBox() {
int[] bbox = new int[4];
bbox[0] = (int)this.bbox[0];
formats.addElement(new GIFReader());
formats.addElement(new PNGReader());
formats.addElement(new TIFFReader());
+ formats.addElement(new EPSReader());
formats.addElement(new SVGReader());
//
private int _fontVariant;
private FontMetric _metric;
+ private int _letterSpacing;
private static Hashtable EMPTY_HASHTABLE = new Hashtable();
_fontName = fontInfo.fontLookup(fontFamily, fontStyle, fontWeight);
_metric = fontInfo.getMetricsFor(_fontName);
_fontVariant = fontVariant;
+ _letterSpacing = 0;
}
+ public FontState(FontInfo fontInfo, String fontFamily, String fontStyle,
+ String fontWeight, int fontSize,
+ int fontVariant, int letterSpacing) throws FOPException {
+ this(fontInfo, fontFamily, fontStyle, fontWeight, fontSize,
+ fontVariant);
+ _letterSpacing = letterSpacing;
+ }
+
+
public int getAscender() {
return _metric.getAscender(_fontSize) / 1000;
}
+ public int getLetterSpacing() {
+ return _letterSpacing;
+ }
+
+
public int getCapHeight() {
return _metric.getCapHeight(_fontSize) / 1000;
}
public int width(int charnum) {
// returns width of given character number in millipoints
- return (_metric.width(charnum, _fontSize) / 1000);
+ return _letterSpacing + (_metric.width(charnum, _fontSize) / 1000);
}
/**
/**
* creates an empty PDF document <p>
- *
+ *
* The constructor creates a /Root and /Pages object to
* track the document but does not write these objects until
* the trailer is written. Note that the object ID of the
}
+ public PDFICCStream makePDFICCStream() {
+ PDFICCStream iccStream = new PDFICCStream(++this.objectcount);
+ this.objects.addElement(iccStream);
+ return iccStream;
+ }
+
/**
* make a Type1 /Font object
*
if (xObject != null)
return xObject.getXNumber();
// else, create a new one
- xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount,
- img);
+ xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount, img, this);
this.objects.addElement(xObject);
this.xObjects.addElement(xObject);
this.xObjectsMap.put(url, xObject);
//next line by lmckenzi@ca.ibm.com
//solves when IDNode made before IDReferences.createID called
//idReferences.createNewId(destination);
-
- idReferences.createUnvalidatedID(destination);
+
+ idReferences.createUnvalidatedID(destination);
idReferences.addToIdValidationList(destination);
goToReference = idReferences.createInternalLinkGoTo(destination,
++this.objectcount);
private int origLength;
private int len1, len3;
private byte[] originalData = null;
-
+
private ColorSpace cs;
-
+
public void setColorSpace(ColorSpace cs) throws java.io.IOException {
this.cs = cs;
setData(cs.getICCProfile());
}
-
+
public PDFICCStream(int num) {
super(num);
cs = null;
}
-
+
public PDFICCStream(int num, ColorSpace cs) throws java.io.IOException {
super(num);
setColorSpace(cs);
}
-
- // overload the base object method so we don't have to copy
- // byte arrays around so much
+
+ // overload the base object method so we don't have to copy
+ // byte arrays around so much
protected int output(java.io.OutputStream stream)
- throws java.io.IOException {
+ throws java.io.IOException {
int length = 0;
String filterEntry = applyFilters();
StringBuffer pb = new StringBuffer();
pb.append(this.number).append(" ").append(this.generation).append(" obj\n<< ");
pb.append("/N ").append(cs.getNumComponents()).append(" ");
-
+
if (cs.getColorSpace() > 0)
pb.append("/Alternate /").append(cs.getColorSpacePDFString()).append(" ");
-
+
pb.append("/Length ").append((_data.size() + 1)).append(" ").append(filterEntry);
pb.append(" >>\n");
byte[] p = pb.toString().getBytes();
length += p.length;
return length;
}
+
+
}
p = "endobj\n".getBytes();
stream.write(p);
length += p.length;
- System.out.println("Embedded Type1 font");
+ //System.out.println("Embedded Type1 font");
return length;
}
public void setData(byte[] data, int size) throws java.io.IOException {
_data.reset();
- System.out.println("Writing " + size + " bytes of font data");
+ //System.out.println("Writing " + size + " bytes of font data");
_data.write(data, 0, size);
}
// FOP
import org.apache.fop.datatypes.ColorSpace;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFICCStream;
import org.apache.fop.image.FopImage;
+import org.apache.fop.image.EPSImage;
+import org.apache.fop.image.JpegImage;
import org.apache.fop.image.FopImageException;
/**
* the dictionary just provides information like the stream length
*/
public class PDFXObject extends PDFObject {
+ private boolean isPS;
+ private PDFDocument pdfDoc;
+ private PDFICCStream pdfICCStream;
FopImage fopimage;
int Xnum;
-
/**
* create an Xobject with the given number and name and load the
* image in the object
*/
public PDFXObject(int number, int Xnumber, FopImage img) {
+ this(number, Xnumber, img, null);
+ }
+
+ public PDFXObject(int number, int Xnumber, FopImage img, PDFDocument pdfdoc) {
super(number);
+ isPS = false;
this.Xnum = Xnumber;
if (img == null)
MessageHandler.errorln("FISH");
fopimage = img;
+ this.pdfDoc = pdfdoc;
+ pdfICCStream = null;
+ try {
+ if (fopimage instanceof JpegImage) {
+ fopimage.getBitmaps();
+ JpegImage jpegimage = (JpegImage)fopimage;
+ if (jpegimage.getColorSpace().hasICCProfile()) {
+ pdfICCStream = pdfDoc.makePDFICCStream();
+ pdfICCStream.setColorSpace(jpegimage.getColorSpace());
+ pdfICCStream.addDefaultFilters();
+ }
+ }
+ } catch (Exception e) {
+ MessageHandler.errorln("Error while reading image " + fopimage.getURL() +
+ ": " + e.getMessage());
+ }
}
/**
protected int output(OutputStream stream) throws IOException {
int length = 0;
int i = 0;
- int x, y;
try {
- // delegate the stream work to PDFStream
- PDFStream imgStream = new PDFStream(0);
-
- imgStream.setData(fopimage.getBitmaps());
-
- /*
- * Added by Eric Dalquist
- * If the DCT filter hasn't been added to the object we add it here
- */
- if (fopimage.getPDFFilter() != null) {
- imgStream.addFilter(fopimage.getPDFFilter());
- }
-
- imgStream.addDefaultFilters();
-
- String dictEntries = imgStream.applyFilters();
-
- String p = this.number + " " + this.generation + " obj\n";
- p = p + "<</Type /XObject\n";
- p = p + "/Subtype /Image\n";
- p = p + "/Name /Im" + Xnum + "\n";
- p = p + "/Length " + imgStream.getDataLength() + "\n";
- p = p + "/Width " + fopimage.getWidth() + "\n";
- p = p + "/Height " + fopimage.getHeight() + "\n";
- p = p + "/BitsPerComponent " + fopimage.getBitsPerPixel() + "\n";
- ColorSpace cs = fopimage.getColorSpace();
- p = p + "/ColorSpace /" + cs.getColorSpacePDFString() + "\n";
- if (fopimage.isTransparent()) {
- PDFColor transp = fopimage.getTransparentColor();
- p = p + "/Mask [" + transp.red255() + " " + transp.red255()
- + " " + transp.green255() + " " + transp.green255() + " "
- + transp.blue255() + " " + transp.blue255() + "]\n";
+ if (fopimage instanceof EPSImage) {
+ isPS = true;
+ EPSImage epsImage = (EPSImage)fopimage;
+ int[] bbox = epsImage.getBBox();
+ int bboxw = bbox[2] - bbox[0];
+ int bboxh = bbox[3] - bbox[1];
+
+ // delegate the stream work to PDFStream
+ PDFStream imgStream = new PDFStream(0);
+
+ StringBuffer preamble = new StringBuffer();
+ preamble.append("%%BeginDocument: " + epsImage.getDocName() + "\n");
+
+ preamble.append("userdict begin % Push userdict on dict stack\n");
+ preamble.append("/PreEPS_state save def\n");
+ preamble.append("/dict_stack countdictstack def\n");
+ preamble.append("/ops_count count 1 sub def\n");
+ preamble.append("/showpage {} def\n");
+
+
+ preamble.append((double)(1f/(double)bboxw) + " " + (double)(1f/(double)bboxh) + " scale\n");
+ preamble.append(-bbox[0] + " " + (-bbox[1]) + " translate\n");
+ preamble.append(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + " rectclip\n");
+ preamble.append("newpath\n");
+
+ StringBuffer post = new StringBuffer();
+ post.append("%%EndDocument\n");
+ post.append("count ops_count sub {pop} repeat\n");
+ post.append("countdictstack dict_stack sub {end} repeat\n");
+ post.append("PreEPS_state restore\n");
+ post.append("end % userdict\n");
+
+ byte[] preBytes = preamble.toString().getBytes();
+ byte[] postBytes = post.toString().getBytes();
+ byte[] imgData = new byte[preBytes.length + postBytes.length + fopimage.getBitmaps().length];
+
+ System.arraycopy (preBytes, 0, imgData, 0, preBytes.length);
+ System.arraycopy (fopimage.getBitmaps(), 0, imgData, preBytes.length, fopimage.getBitmaps().length);
+ System.arraycopy (postBytes, 0, imgData, preBytes.length + fopimage.getBitmaps().length, postBytes.length);
+
+
+ imgStream.setData(imgData);
+ //imgStream.addFilter(new FlateFilter());
+ imgStream.addDefaultFilters();
+
+ String dictEntries = imgStream.applyFilters();
+
+ String p = this.number + " " + this.generation + " obj\n";
+ p = p + "<</Type /XObject\n";
+ p = p + "/Subtype /PS\n";
+ p = p + "/Length " + imgStream.getDataLength();
+
+ // don't know if it's the good place (other objects can have references to it)
+ fopimage.close();
+ p = p + dictEntries;
+ p = p + ">>\n";
+
+ // push the pdf dictionary on the writer
+ byte[] pdfBytes = p.getBytes();
+ stream.write(pdfBytes);
+ length += pdfBytes.length;
+ // push all the image data on the writer and takes care of length for trailer
+ length += imgStream.outputStreamData(stream);
+
+ pdfBytes = ("endobj\n").getBytes();
+ stream.write(pdfBytes);
+ length += pdfBytes.length;
+
+ } else {
+
+ // delegate the stream work to PDFStream
+ PDFStream imgStream = new PDFStream(0);
+
+ imgStream.setData(fopimage.getBitmaps());
+
+ /*
+ * Added by Eric Dalquist
+ * If the DCT filter hasn't been added to the object we add it here
+ */
+ if (fopimage.getPDFFilter() != null) {
+ imgStream.addFilter(fopimage.getPDFFilter());
+ }
+
+ imgStream.addDefaultFilters();
+
+ String dictEntries = imgStream.applyFilters();
+
+ String p = this.number + " " + this.generation + " obj\n";
+ p = p + "<</Type /XObject\n";
+ p = p + "/Subtype /Image\n";
+ p = p + "/Name /Im" + Xnum + "\n";
+ p = p + "/Length " + imgStream.getDataLength() + "\n";
+ p = p + "/Width " + fopimage.getWidth() + "\n";
+ p = p + "/Height " + fopimage.getHeight() + "\n";
+ p = p + "/BitsPerComponent " + fopimage.getBitsPerPixel() + "\n";
+
+ if (pdfICCStream != null ) {
+ p = p + "/ColorSpace [/ICCBased " + pdfICCStream.referencePDF() + "]\n";
+ } else {
+ ColorSpace cs = fopimage.getColorSpace();
+ p = p + "/ColorSpace /" + cs.getColorSpacePDFString() + "\n";
+ }
+
+ /* PhotoShop generates CMYK values that's inverse,
+ */
+ if (fopimage.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK &&
+ fopimage.invertImage()) {
+ p = p + "/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.1 0.0 ]\n";
+ }
+
+ if (fopimage.isTransparent()) {
+ PDFColor transp = fopimage.getTransparentColor();
+ p = p + "/Mask [" + transp.red255() + " " + transp.red255()
+ + " " + transp.green255() + " " + transp.green255() + " "
+ + transp.blue255() + " " + transp.blue255() + "]\n";
+ }
+ p = p + dictEntries;
+ p = p + ">>\n";
+
+ // don't know if it's the good place (other objects can have references to it)
+ fopimage.close();
+
+ // push the pdf dictionary on the writer
+ byte[] pdfBytes = p.getBytes();
+ stream.write(pdfBytes);
+ length += pdfBytes.length;
+ // push all the image data on the writer and takes care of length for trailer
+ length += imgStream.outputStreamData(stream);
+
+ pdfBytes = ("endobj\n").getBytes();
+ stream.write(pdfBytes);
+ length += pdfBytes.length;
}
- p = p + dictEntries;
- p = p + ">>\n";
-
- // don't know if it's the good place (other objects can have references to it)
- fopimage.close();
-
- // push the pdf dictionary on the writer
- byte[] pdfBytes = p.getBytes();
- stream.write(pdfBytes);
- length += pdfBytes.length;
- // push all the image data on the writer and takes care of length for trailer
- length += imgStream.outputStreamData(stream);
-
- pdfBytes = ("endobj\n").getBytes();
- stream.write(pdfBytes);
- length += pdfBytes.length;
} catch (FopImageException imgex) {
MessageHandler.errorln("Error in XObject : "
+ imgex.getMessage());
addWordLines(area, rx, bl, size, areaColor);
+ // Set letterSpacing
+ float ls = area.getFontState().getLetterSpacing() / this.currentFontSize;
+ pdf.append(ls).append(" Tc\n");
+
if (!textOpen || bl != prevWordY) {
closeText();
prevWordWidth = area.getContentWidth();
prevWordX = rx;
-
String s;
if (area.getPageNumberID()
!= null) { // this text is a page number, so resolve it
}
}
+
public void render(Page page, OutputStream outputStream)
throws FOPException, IOException {
// log.debug("rendering single page to PDF");
import org.apache.fop.render.Renderer;
import org.apache.fop.image.ImageArea;
import org.apache.fop.image.FopImage;
+import org.apache.fop.image.JpegImage;
import org.apache.fop.image.FopImageException;
import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.*;
write("/M/moveto ld");
write("/RM/rmoveto ld");
write("/t/show ld");
+ write("/A/ashow ld");
write("/ux 0.0 def");
write("/uy 0.0 def");
BridgeContext ctx = new BridgeContext(userAgent);
GraphicsNode root;
- try {
+ try {
root = builder.build(ctx, doc);
- } catch (Exception e) {
+ } catch (Exception e) {
log.error("svg graphic could not be built: "
- + e.getMessage(), e);
+ + e.getMessage(), e);
return;
}
// get the 'width' and 'height' attributes of the SVG document
movetoCurrPosition();
}
+ public void renderEPS(FopImage img, int x, int y, int w, int h) {
+ try {
+ EPSImage eimg = (EPSImage)img;
+ int[] bbox = eimg.getBBox();
+ int bboxw = bbox[2] - bbox[0];
+ int bboxh = bbox[3] - bbox[1];
+
+
+ write("%%BeginDocument: " + eimg.getDocName());
+ write("BeginEPSF");
+
+ write(x + " " + (y - h) + " translate");
+ write("0.0 rotate");
+ write((long)(w/bboxw) + " " + (long)(h/bboxh) + " scale");
+ write(-bbox[0] + " " + (-bbox[1]) + " translate");
+ write(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + " rectclip");
+ write("newpath");
+ out.writeByteArr(img.getBitmaps());
+ write("%%EndDocument");
+ write("EndEPSF");
+ write("");
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
+ + e.getMessage() + ")", e);
+ }
+ }
+
public void renderBitmap(FopImage img, int x, int y, int w, int h) {
try {
boolean iscolor = img.getColorSpace().getColorSpace()
byte[] imgmap = img.getBitmaps();
write("gsave");
- write("/DeviceRGB setcolorspace");
+ if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK)
+ write("/DeviceCMYK setcolorspace");
+ else
+ write("/DeviceRGB setcolorspace");
+
write(x + " " + (y - h) + " translate");
write(w + " " + h + " scale");
write("<<");
write(" /Width " + img.getWidth());
write(" /Height " + img.getHeight());
write(" /BitsPerComponent 8");
- if (iscolor) {
+ if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK) {
+ if (img.invertImage())
+ write(" /Decode [1 0 1 0 1 0 1 0]");
+ else
+ write(" /Decode [0 1 0 1 0 1 0 1]");
+ } else if (iscolor) {
write(" /Decode [0 1 0 1 0 1]");
} else {
write(" /Decode [0 1]");
// Setup scanning for left-to-right and top-to-bottom
write(" /ImageMatrix [" + img.getWidth() + " 0 0 -"
+ img.getHeight() + " 0 " + img.getHeight() + "]");
- write(" /DataSource currentfile /ASCII85Decode filter /FlateDecode filter");
+
+ if (img instanceof JpegImage)
+ write(" /DataSource currentfile /ASCII85Decode filter /DCTDecode filter");
+ else
+ write(" /DataSource currentfile /ASCII85Decode filter /FlateDecode filter");
// write(" /DataSource currentfile /ASCIIHexDecode filter /FlateDecode filter");
// write(" /DataSource currentfile /ASCII85Decode filter /RunLengthDecode filter");
// write(" /DataSource currentfile /ASCIIHexDecode filter /RunLengthDecode filter");
InputStream bain = new ByteArrayInputStream(imgmap);
InputStream in;
in = bain;
- in = FlateEncodeFilter.filter(in);
+ if (!(img instanceof JpegImage))
+ in = FlateEncodeFilter.filter(in);
// in = RunLengthEncodeFilter.filter(in);
// in = ASCIIHexEncodeFilter.filter(in);
in = ASCII85EncodeFilter.filter(in);
imagecount++;
// if (imagecount!=4) return;
- comment("% --- ImageArea");
+ comment("% --- ImageArea");
if (area.getImage() instanceof SVGImage) {}
- else {
+ else if (area.getImage() instanceof EPSImage) {
+ renderEPS(area.getImage(), x, y, w, h);
+ } else {
renderBitmap(area.getImage(), x, y, w, h);
}
comment("% --- ImageArea end");
s = area.getText();
}
int l = s.length();
-
+
for (int i = 0; i < l; i++) {
char ch = s.charAt(i);
char mch = fs.mapChar(ch);
sb = sb.append(mch);
}
}
+
+ String psString = null;
+ if (area.getFontState().getLetterSpacing() > 0) {
+ float f = area.getFontState().getLetterSpacing() * 1000 / this.currentFontSize;
+ psString = (new StringBuffer().append(f).append(" 0.0 (").append(sb).
+ append(") A")).toString();
+ } else {
+ psString = (new StringBuffer("(").append(sb).append(") t")).toString();
+ }
+
+
// System.out.println("["+s+"] --> ["+sb.toString()+"]");
// comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString());
if (area.getUnderlined() || area.getLineThrough()
|| area.getOverlined())
write("ULS");
- write("(" + sb.toString() + ") t");
+ write(psString);
if (area.getUnderlined())
write("ULE");
if (area.getLineThrough())
write("%%EndProlog");
write("%%BeginSetup");
writeFontDict(fontInfo);
+
+ /* Write proc for including EPS */
+ write("%%BeginResource: procset EPSprocs");
+ write("%%Title: EPS encapsulation procs");
+
+ write("/BeginEPSF { %def");
+ write("/b4_Inc_state save def % Save state for cleanup");
+ write("/dict_count countdictstack def % Count objects on dict stack");
+ write("/op_count count 1 sub def % Count objects on operand stack");
+ write("userdict begin % Push userdict on dict stack");
+ write("/showpage { } def % Redefine showpage, { } = null proc");
+ write("0 setgray 0 setlinecap % Prepare graphics state");
+ write("1 setlinewidth 0 setlinejoin");
+ write("10 setmiterlimit [ ] 0 setdash newpath");
+ write("/languagelevel where % If level not equal to 1 then");
+ write("{pop languagelevel % set strokeadjust and");
+ write("1 ne % overprint to their defaults.");
+ write("{false setstrokeadjust false setoverprint");
+ write("} if");
+ write("} if");
+ write("} bind def");
+
+ write("/EndEPSF { %def");
+ write("count op_count sub {pop} repeat % Clean up stacks");
+ write("countdictstack dict_count sub {end} repeat");
+ write("b4_Inc_state restore");
+ write("} bind def");
+ write("%%EndResource");
+
write("%%EndSetup");
write("FOPFonts begin");
}
write('\n');
}
+ public void writeByteArr(byte[] cmd) throws IOException {
+ write(cmd);
+ write('\n');
+ }
}