diff options
Diffstat (limited to 'src/org/apache')
-rw-r--r-- | src/org/apache/fop/datatypes/ColorSpace.java | 58 | ||||
-rw-r--r-- | src/org/apache/fop/image/EPSImage.java | 94 | ||||
-rw-r--r-- | src/org/apache/fop/image/FopImageFactory.java | 2 | ||||
-rw-r--r-- | src/org/apache/fop/image/JpegImage.java | 111 | ||||
-rw-r--r-- | src/org/apache/fop/image/analyser/EPSReader.java | 224 | ||||
-rw-r--r-- | src/org/apache/fop/image/analyser/ImageReaderFactory.java | 1 | ||||
-rw-r--r-- | src/org/apache/fop/pdf/PDFDocument.java | 16 | ||||
-rw-r--r-- | src/org/apache/fop/pdf/PDFICCStream.java | 57 | ||||
-rw-r--r-- | src/org/apache/fop/pdf/PDFXObject.java | 223 | ||||
-rw-r--r-- | src/org/apache/fop/render/ps/PSRenderer.java | 29 | ||||
-rw-r--r-- | src/org/apache/fop/render/ps/PSStream.java | 8 |
11 files changed, 713 insertions, 110 deletions
diff --git a/src/org/apache/fop/datatypes/ColorSpace.java b/src/org/apache/fop/datatypes/ColorSpace.java index 9b289369f..35a6987e6 100644 --- a/src/org/apache/fop/datatypes/ColorSpace.java +++ b/src/org/apache/fop/datatypes/ColorSpace.java @@ -8,36 +8,74 @@ 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_UNKNOWN = -1; public static int DEVICE_GRAY = 1; // what's the *official* spelling? // public static int DEVICE_GREY = 1; 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(); } - - public int getColorSpace() { - return (this.currentColorSpace); + + 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 int getNumComponents() { + return numComponents; + } + public String getColorSpacePDFString() { // this is for PDF Output. Does anyone else need a string representation? - - + + // shouldn't this be a select-case? I can never remember // the syntax for that. if (this.currentColorSpace == this.DEVICE_RGB) { @@ -50,5 +88,5 @@ public class ColorSpace { return ("DeviceRGB"); } } - + } diff --git a/src/org/apache/fop/image/EPSImage.java b/src/org/apache/fop/image/EPSImage.java new file mode 100644 index 000000000..ada6fbfcf --- /dev/null +++ b/src/org/apache/fop/image/EPSImage.java @@ -0,0 +1,94 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.image; + +// Java +import java.net.URL; +import java.net.URLConnection; +import java.io.InputStream; +import java.io.IOException; + +// 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; +import org.apache.fop.image.analyser.EPSReader; + +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + + +/** + * @see AbstractFopImage + * @see FopImage + */ +public class EPSImage extends AbstractFopImage { + private String docName; + private int[] bbox; + + private byte[] epsImage = null; + private EPSReader epsReader = null; + + /** + * 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 + */ + public String getDocName() { + return docName; + } + + /** + * 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); + init(href); + if (imgReader instanceof EPSReader) { + EPSReader eimgReader = (EPSReader)imgReader; + epsReader = eimgReader; + epsImage = eimgReader.getEpsFile(); + m_bitmaps = epsImage; + bbox = eimgReader.getBBox(); + } + } + + protected void loadImage() throws FopImageException { + // Image is loaded in reader + } + + public byte[] getEPSImage() throws FopImageException { + if (epsImage == null) + MessageHandler.errorln("ERROR LOADING EXTERNAL EPS"); + return epsImage; + } + +} diff --git a/src/org/apache/fop/image/FopImageFactory.java b/src/org/apache/fop/image/FopImageFactory.java index cd777f2e2..b9cbec594 100644 --- a/src/org/apache/fop/image/FopImageFactory.java +++ b/src/org/apache/fop/image/FopImageFactory.java @@ -132,6 +132,8 @@ public class FopImageFactory { } else if ("image/bmp".equals(imgMimeType)) { imgClassName = "org.apache.fop.image.BmpImage"; // imgClassName = "org.apache.fop.image.JAIImage"; + } else if ("image/eps".equals(imgMimeType)) { + imgClassName = "org.apache.fop.image.EPSImage"; } else if ("image/png".equals(imgMimeType)) { imgClassName = "org.apache.fop.image.JimiImage"; // imgClassName = "org.apache.fop.image.JAIImage"; diff --git a/src/org/apache/fop/image/JpegImage.java b/src/org/apache/fop/image/JpegImage.java index e725b79f5..23974cd6b 100644 --- a/src/org/apache/fop/image/JpegImage.java +++ b/src/org/apache/fop/image/JpegImage.java @@ -28,30 +28,34 @@ import org.apache.fop.image.analyser.ImageReader; * @see FopImage */ public class JpegImage extends AbstractFopImage { + boolean found_icc_profile = false; + boolean found_dimensions = false; + public JpegImage(URL href) throws FopImageException { super(href); } - + public JpegImage(URL href, ImageReader imgReader) throws FopImageException { super(href, imgReader); } - + 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; boolean cont = true; - + this.m_compressionType = new DCTFilter(); this.m_compressionType.setApplied(true); - + try { inStream = this.m_href.openStream(); - + while ((bytes_read = inStream.read(readBuf)) != -1) { baos.write(readBuf, 0, bytes_read); } @@ -60,70 +64,96 @@ public class JpegImage extends AbstractFopImage { this.m_href.toString() + " : " + ex.getClass() + " - " + ex.getMessage()); } - + this.m_bitmaps = baos.toByteArray(); this.m_bitsPerPixel = 8; this.m_isTransparent = false; - + if (this.m_bitmaps.length > (index + 2) && - uByte(this.m_bitmaps[index]) == 255 && - uByte(this.m_bitmaps[index + 1]) == 216) { + uByte(this.m_bitmaps[index]) == 255 && + uByte(this.m_bitmaps[index + 1]) == 216) { index += 2; - + while (index < this.m_bitmaps.length && cont) { - //check to be sure this is the begining of a header + //check to be sure this is the begining of a header if (this.m_bitmaps.length > (index + 2) && - uByte(this.m_bitmaps[index]) == 255) { - - //192 or 194 are the header bytes that contain the jpeg width height and color depth. + uByte(this.m_bitmaps[index]) == 255) { + + //192 or 194 are the header bytes that contain the jpeg width height and color depth. if (uByte(this.m_bitmaps[index + 1]) == 192 || - uByte(this.m_bitmaps[index + 1]) == 194) { - + uByte(this.m_bitmaps[index + 1]) == 194) { + this.m_height = calcBytes(this.m_bitmaps[index + 5], this.m_bitmaps[index + 6]); this.m_width = calcBytes(this.m_bitmaps[index + 7], 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; } - - cont = false; - break; - - } else { // if (uByte(this.m_bitmaps[index + 1]) == headers[headerIndex]) { + 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); + + if ("ICC_PROFILE".equals(new String(icc_string))){ + int chunkSize = calcBytes(this.m_bitmaps[index + 2], + this.m_bitmaps[index + 3]) + 2; + + if (iccStream.size() == 0) + iccStream.write(this.m_bitmaps, index+18, + chunkSize - 20); + else + iccStream.write(this.m_bitmaps, index+16, + chunkSize - 18); + + } + + 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."); + 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()); } } - + private int calcBytes(byte bOne, byte bTwo) { return (uByte(bOne) * 256) + uByte(bTwo); } - + private int uByte(byte bIn) { if (bIn < 0) { return 256 + bIn; @@ -133,4 +163,3 @@ public class JpegImage extends AbstractFopImage { } } - diff --git a/src/org/apache/fop/image/analyser/EPSReader.java b/src/org/apache/fop/image/analyser/EPSReader.java new file mode 100644 index 000000000..dcdf2a46b --- /dev/null +++ b/src/org/apache/fop/image/analyser/EPSReader.java @@ -0,0 +1,224 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.image.analyser; + +// Java +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +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 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 + long psStart = 0; + long psLength = 0; + long wmfStart = 0; + long wmfLength = 0; + long tiffStart = 0; + long tiffLength = 0; + + /** raw eps file */ + private byte[] rawEps; + /** 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)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); + } + + public boolean verifySignature(String uri, BufferedInputStream fis) + 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 + 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 + byte[] epsh = "%!PS".getBytes(); + if (epsh[0] == header[0] && + epsh[1] == header[1] && + epsh[2] == header[2] && + epsh[3] == header[3]) { + isAscii = true; + 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 + isEPS = false; + } + } + + return isEPS; + } + + /** read the eps file and extract eps part */ + private void readEPSImage(BufferedInputStream fis) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] file; + byte[] readBuf = new byte[20480]; + 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(file, 0, epsFile, 0, epsFile.length); + } else { + rawEps = new byte[file.length]; + epsFile = new byte[(int)psLength]; + System.arraycopy(file, 0, rawEps, 0, rawEps.length); + System.arraycopy(rawEps, (int)psStart, epsFile, 0, (int)psLength); + } + } + + public byte[] getEpsFile() { + return epsFile; + } + + /* Get embedded preview or null */ + public byte[] getPreview() { + InputStream is = null; + if (preview == null) { + if (tiffLength > 0) { + preview = new byte[(int)tiffLength]; + System.arraycopy(rawEps, (int)tiffStart, preview, 0, (int)tiffLength); + } + } + return preview; + } + + /** 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; + for (i = idx; sfound && (i-idx) < bbxName.length; i++) { + if (bbxName[i - idx] != epsFile[i]) + sfound = false; + } + if (sfound) { + found = true; + idx = i; + } else { + 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++; + + int nidx = idx; + + while (nidx < epsFile.length && + (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 + */ + public int[] getBBox() { + int[] bbox = new int[4]; + bbox[0] = (int)this.bbox[0]; + bbox[1] = (int)this.bbox[1]; + bbox[2] = (int)this.bbox[2]; + bbox[3] = (int)this.bbox[3]; + return bbox; + } +} + diff --git a/src/org/apache/fop/image/analyser/ImageReaderFactory.java b/src/org/apache/fop/image/analyser/ImageReaderFactory.java index e9b5ce3f0..f2c2160b7 100644 --- a/src/org/apache/fop/image/analyser/ImageReaderFactory.java +++ b/src/org/apache/fop/image/analyser/ImageReaderFactory.java @@ -42,6 +42,7 @@ public class ImageReaderFactory { formats.addElement(new GIFReader()); formats.addElement(new PNGReader()); formats.addElement(new TIFFReader()); + formats.addElement(new EPSReader()); formats.addElement(new SVGReader()); // diff --git a/src/org/apache/fop/pdf/PDFDocument.java b/src/org/apache/fop/pdf/PDFDocument.java index b21fc706f..e422a69f1 100644 --- a/src/org/apache/fop/pdf/PDFDocument.java +++ b/src/org/apache/fop/pdf/PDFDocument.java @@ -758,7 +758,19 @@ public class PDFDocument { return encoding; } - + /** + * Create a PDFICCStream + @see PDFXObject + @see org.apache.fop.image.JpegImage + @see org.apache.fop.datatypes.ColorSpace + */ + public PDFICCStream makePDFICCStream() { + PDFICCStream iccStream = new PDFICCStream(++this.objectcount); + this.objects.addElement(iccStream); + return iccStream; + } + + /** * make a Type1 /Font object * @@ -917,7 +929,7 @@ public class PDFDocument { return xObject.getXNumber(); // else, create a new one xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount, - img); + img, this); this.objects.add(xObject); this.xObjects.add(xObject); this.xObjectsMap.put(url, xObject); diff --git a/src/org/apache/fop/pdf/PDFICCStream.java b/src/org/apache/fop/pdf/PDFICCStream.java new file mode 100644 index 000000000..7890b51a9 --- /dev/null +++ b/src/org/apache/fop/pdf/PDFICCStream.java @@ -0,0 +1,57 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.pdf; +import org.apache.fop.datatypes.ColorSpace; + +public class PDFICCStream extends PDFStream { + 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 + protected int output(java.io.OutputStream stream) + 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(); + stream.write(p); + length += p.length; + length += outputStreamData(stream); + p = "endobj\n".getBytes(); + stream.write(p); + length += p.length; + return length; + } +} diff --git a/src/org/apache/fop/pdf/PDFXObject.java b/src/org/apache/fop/pdf/PDFXObject.java index cefff8a08..989008321 100644 --- a/src/org/apache/fop/pdf/PDFXObject.java +++ b/src/org/apache/fop/pdf/PDFXObject.java @@ -17,7 +17,11 @@ import java.io.OutputStream; // 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; /** @@ -28,23 +32,51 @@ 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) { + /* hasICCProfile is not initialized before + the bitmaps is read - should maybe fix this in + the JpegImage instead... + */ + 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()); + } } - + /** * @return the PDF XObject number */ @@ -58,66 +90,147 @@ public class PDFXObject extends PDFObject { 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.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, + this will invert the values - too bad if it's not a PhotoShop image...*/ + if (fopimage.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK) { + 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()); } - + return length; } - + byte[] toPDF() { return null; } diff --git a/src/org/apache/fop/render/ps/PSRenderer.java b/src/org/apache/fop/render/ps/PSRenderer.java index 08f17b3f9..6a5699cec 100644 --- a/src/org/apache/fop/render/ps/PSRenderer.java +++ b/src/org/apache/fop/render/ps/PSRenderer.java @@ -311,6 +311,35 @@ public class PSRenderer extends AbstractRenderer { 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"); } diff --git a/src/org/apache/fop/render/ps/PSStream.java b/src/org/apache/fop/render/ps/PSStream.java index 9b03c11fd..2643a6c5a 100644 --- a/src/org/apache/fop/render/ps/PSStream.java +++ b/src/org/apache/fop/render/ps/PSStream.java @@ -14,12 +14,16 @@ public class PSStream extends FilterOutputStream { public PSStream(OutputStream out) { super(out); } - + public void write(String cmd) throws IOException { if (cmd.length() > 255) throw new RuntimeException("PostScript command exceeded limit of 255 characters"); write(cmd.getBytes("US-ASCII")); write('\n'); } - + + public void writeByteArr(byte[] cmd) throws IOException { + write(cmd); + write('\n'); + } } |