diff options
19 files changed, 528 insertions, 237 deletions
diff --git a/src/java-1.4/org/apache/fop/image/ImageIOImage.java b/src/java-1.4/org/apache/fop/image/ImageIOImage.java index 369bb6e8d..882f36d92 100644 --- a/src/java-1.4/org/apache/fop/image/ImageIOImage.java +++ b/src/java-1.4/org/apache/fop/image/ImageIOImage.java @@ -42,9 +42,20 @@ public class ImageIOImage extends AbstractFopImage { super(info); } + /** + * @see org.apache.fop.image.AbstractFopImage#loadDimensions() + */ + protected boolean loadDimensions() { + if (this.bitmaps == null) { + return loadBitmap(); + } + return true; + } + /** @see org.apache.fop.image.AbstractFopImage#loadBitmap() */ protected boolean loadBitmap() { try { + inputStream.reset(); BufferedImage imageData = ImageIO.read(inputStream); this.height = imageData.getHeight(); diff --git a/src/java/org/apache/fop/image/BatikImage.java b/src/java/org/apache/fop/image/BatikImage.java index b0987906e..9c99eb465 100644 --- a/src/java/org/apache/fop/image/BatikImage.java +++ b/src/java/org/apache/fop/image/BatikImage.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 The Apache Software Foundation + * Copyright 2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,16 @@ public abstract class BatikImage extends AbstractFopImage { private byte[] softMask = null; /** + * The InputStream wrapped into a SeekableStream for decoding. + */ + protected SeekableStream seekableInput = null; + + /** + * The Batik representation of the image + */ + protected CachableRed cr = null; + + /** * Constructs a new BatikImage instance. * @param imgReader basic metadata for the image */ @@ -54,11 +64,72 @@ public abstract class BatikImage extends AbstractFopImage { * @see org.apache.fop.image.AbstractFopImage#loadDimensions() */ protected boolean loadDimensions() { - if (this.bitmaps == null) { - loadImage(); - } + if (seekableInput == null && inputStream != null) { + try { + seekableInput = new FileCacheSeekableStream(inputStream); + } catch (IOException ioe) { + seekableInput = new MemoryCacheSeekableStream(inputStream); + } + try { + this.bitsPerPixel = 8; + cr = decodeImage(seekableInput); + this.height = cr.getHeight(); + this.width = cr.getWidth(); + this.isTransparent = false; + this.softMask = null; + ColorModel cm = cr.getColorModel(); + + this.height = cr.getHeight(); + this.width = cr.getWidth(); + this.isTransparent = false; + this.softMask = null; + + int transparencyType = cm.getTransparency(); + if (cm instanceof IndexColorModel) { + if (transparencyType == Transparency.BITMASK) { + // Use 'transparent color'. + IndexColorModel icm = (IndexColorModel)cm; + int numColor = icm.getMapSize(); + byte [] alpha = new byte[numColor]; + icm.getAlphas(alpha); + for (int i = 0; i < numColor; i++) { + if ((alpha[i] & 0xFF) == 0) { + this.isTransparent = true; + int red = (icm.getRed (i)) & 0xFF; + int grn = (icm.getGreen(i)) & 0xFF; + int blu = (icm.getBlue (i)) & 0xFF; + this.transparentColor = new Color(red, grn, blu); + break; + } + } + } + } else { + cr = new Any2sRGBRed(cr); + } - return this.bitmaps != null; + // Get our current ColorModel + cm = cr.getColorModel(); + if (this.colorSpace == null) { + this.colorSpace = cm.getColorSpace(); + } + } catch (IOException ioe) { + log.error("Error while loading image (Batik): " + ioe.getMessage(), ioe); + try { + seekableInput.close(); + } catch (IOException ioex) { + // ignore + } + try { + inputStream.close(); + } catch (IOException ioex) { + // ignore + } + seekableInput = null; + inputStream = null; + return false; + } + } + return this.height != -1; } /** @@ -106,88 +177,62 @@ public abstract class BatikImage extends AbstractFopImage { * Loads the image from the InputStream. */ protected void loadImage() { - try { - SeekableStream seekableInput; - try { seekableInput = new FileCacheSeekableStream(inputStream); - } catch (IOException ioe) { - seekableInput = new MemoryCacheSeekableStream(inputStream); - } - - CachableRed cr = decodeImage(seekableInput); - ColorModel cm = cr.getColorModel(); - - this.height = cr.getHeight(); - this.width = cr.getWidth(); - this.isTransparent = false; - this.softMask = null; - this.bitmapsSize = this.width * this.height * 3; - this.bitmaps = new byte[this.bitmapsSize]; - this.bitsPerPixel = 8; - - int transparencyType = cm.getTransparency(); - if (cm instanceof IndexColorModel) { - if (transparencyType == Transparency.BITMASK) { - // Use 'transparent color'. - IndexColorModel icm = (IndexColorModel)cm; - int numColor = icm.getMapSize(); - byte [] alpha = new byte[numColor]; - icm.getAlphas(alpha); - for (int i = 0; i < numColor; i++) { - if ((alpha[i] & 0xFF) == 0) { - this.isTransparent = true; - int red = (icm.getRed (i)) & 0xFF; - int grn = (icm.getGreen(i)) & 0xFF; - int blu = (icm.getBlue (i)) & 0xFF; - this.transparentColor = new Color(red, grn, blu); - break; + if (loadDimensions()) { + try { + // Get our current ColorModel + ColorModel cm = cr.getColorModel(); + + // It has an alpha channel so generate a soft mask. + if (!this.isTransparent && cm.hasAlpha()) + this.softMask = new byte[this.width * this.height]; + + this.bitmapsSize = this.width * this.height * 3; + this.bitmaps = new byte[this.bitmapsSize]; + + WritableRaster wr = (WritableRaster)cr.getData(); + BufferedImage bi = new BufferedImage + (cm, wr.createWritableTranslatedChild(0, 0), + cm.isAlphaPremultiplied(), null); + int [] tmpMap = new int[this.width]; + int idx = 0; + int sfIdx = 0; + for (int y = 0; y < this.height; y++) { + tmpMap = bi.getRGB(0, y, this.width, 1, tmpMap, 0, this.width); + if (softMask != null) { + for (int x = 0; x < this.width; x++) { + int pix = tmpMap[x]; + this.softMask[sfIdx++] = (byte)(pix >>> 24); + this.bitmaps[idx++] = (byte)((pix >>> 16) & 0xFF); + this.bitmaps[idx++] = (byte)((pix >>> 8) & 0xFF); + this.bitmaps[idx++] = (byte)((pix) & 0xFF); + } + } else { + for (int x = 0; x < this.width; x++) { + int pix = tmpMap[x]; + this.bitmaps[idx++] = (byte)((pix >> 16) & 0xFF); + this.bitmaps[idx++] = (byte)((pix >> 8) & 0xFF); + this.bitmaps[idx++] = (byte)((pix) & 0xFF); + } } } - } - } else { - cr = new Any2sRGBRed(cr); - } - - // Get our current ColorModel - cm = cr.getColorModel(); - - // It has an alpha channel so generate a soft mask. - if (!this.isTransparent && cm.hasAlpha()) - this.softMask = new byte[this.width * this.height]; - - this.colorSpace = cm.getColorSpace(); - WritableRaster wr = (WritableRaster)cr.getData(); - BufferedImage bi = new BufferedImage - (cm, wr.createWritableTranslatedChild(0, 0), - cm.isAlphaPremultiplied(), null); - int [] tmpMap = new int[this.width]; - int idx = 0; - int sfIdx = 0; - for (int y = 0; y < this.height; y++) { - tmpMap = bi.getRGB(0, y, this.width, 1, tmpMap, 0, this.width); - if (softMask != null) { - for (int x = 0; x < this.width; x++) { - int pix = tmpMap[x]; - this.softMask[sfIdx++] = (byte)(pix >>> 24); - this.bitmaps[idx++] = (byte)((pix >>> 16) & 0xFF); - this.bitmaps[idx++] = (byte)((pix >>> 8) & 0xFF); - this.bitmaps[idx++] = (byte)((pix) & 0xFF); - } - } else { - for (int x = 0; x < this.width; x++) { - int pix = tmpMap[x]; - this.bitmaps[idx++] = (byte)((pix >> 16) & 0xFF); - this.bitmaps[idx++] = (byte)((pix >> 8) & 0xFF); - this.bitmaps[idx++] = (byte)((pix) & 0xFF); - } + } catch (Exception ex) { + log.error("Error while loading image (Batik): " + ex.getMessage(), ex); + } finally { + // Make sure we clean up + try { + seekableInput.close(); + } catch (IOException ioex) { + // ignore + } + try { + inputStream.close(); + } catch (IOException ioex) { + // ignore } + seekableInput = null; + inputStream = null; + cr = null; } - } catch (Exception ex) { - log.error("Error loading an image" , ex); - /*throw new FopImageException("Error while loading image " - + "" + " : " - + ex.getClass() + " - " - + ex.getMessage()); - */ } } }; diff --git a/src/java/org/apache/fop/image/BmpImage.java b/src/java/org/apache/fop/image/BmpImage.java index 02346b7e6..3cffc4642 100644 --- a/src/java/org/apache/fop/image/BmpImage.java +++ b/src/java/org/apache/fop/image/BmpImage.java @@ -82,14 +82,17 @@ public class BmpImage extends AbstractFopImage { countr++; } } - } catch (IOException e) { - log.error("Error while loading image " - + "" + " : " - + e.getClass() + " - " - + e.getMessage(), e); + } catch (IOException ex) { + log.error("Error while loading image (Bmp): " + ex.getMessage(), ex); + try { + inputStream.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + inputStream = null; return false; } - // gets h & w from headermap + // gets h & w from headermap this.width = headermap[wpos] + headermap[wpos + 1] * 256 + headermap[wpos + 2] * 256 * 256 @@ -140,14 +143,16 @@ public class BmpImage extends AbstractFopImage { temp[count++] = input; } } - inputStream.close(); - inputStream = null; - } catch (IOException e) { - log.error("Error while loading image " - + "" + " : " - + e.getClass() + " - " - + e.getMessage(), e); + } catch (IOException ex) { + log.error("Error while loading image (Bmp): " + ex.getMessage(), ex); return false; + } finally { + try { + inputStream.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + inputStream = null; } for (int i = 0; i < this.height; i++) { @@ -159,9 +164,8 @@ public class BmpImage extends AbstractFopImage { if (this.bitsPerPixel == 24 && x < this.width) { int countr = 2; do { - this.bitmaps[3 * (i * this.width + x) + countr] = - (byte)(temp[(this.height - i - 1) - * bytes + j] & 0xFF); + this.bitmaps[3 * (i * this.width + x) + countr] + = (byte)(temp[(this.height - i - 1) * bytes + j] & 0xFF); j++; } while (--countr >= 0) ; diff --git a/src/java/org/apache/fop/image/GifImage.java b/src/java/org/apache/fop/image/GifImage.java index 5cb95747c..3cafef559 100644 --- a/src/java/org/apache/fop/image/GifImage.java +++ b/src/java/org/apache/fop/image/GifImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import java.net.URLConnection; * @see FopImage */ public class GifImage extends AbstractFopImage { + /** * Create a new gif image. * @@ -52,7 +53,6 @@ public class GifImage extends AbstractFopImage { * To decode the image a dummy URLConnection is used that * will do the conversion. * - * @param ua the user agent for loading * @return True if the load process succeeded */ protected boolean loadBitmap() { @@ -83,9 +83,6 @@ public class GifImage extends AbstractFopImage { return false; } - inputStream.close(); - inputStream = null; - ColorModel cm = consumer.getColorModel(); this.bitsPerPixel = 8; // this.bitsPerPixel = cm.getPixelSize(); @@ -143,11 +140,15 @@ public class GifImage extends AbstractFopImage { this.isTransparent = false; } } catch (Exception ex) { - log.error("Error while loading image " - + "" + " : " - + ex.getClass() + " - " - + ex.getMessage(), ex); + log.error("Error while loading image (Gif): " + ex.getMessage(), ex); return false; + } finally { + try { + inputStream.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + inputStream = null; } // Should take care of the ColorSpace and bitsPerPixel @@ -159,12 +160,9 @@ public class GifImage extends AbstractFopImage { int r = (p >> 16) & 0xFF; int g = (p >> 8) & 0xFF; int b = (p) & 0xFF; - this.bitmaps[3 * (i * this.width + j)] = - (byte)(r & 0xFF); - this.bitmaps[3 * (i * this.width + j) + 1] = - (byte)(g & 0xFF); - this.bitmaps[3 * (i * this.width + j) + 2] = - (byte)(b & 0xFF); + this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF); + this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF); + this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF); } } return true; @@ -181,18 +179,30 @@ public class GifImage extends AbstractFopImage { inputStream = is; } + /** + * @see java.net.URLConnection#getInputStream() + */ public InputStream getInputStream() throws IOException { return inputStream; } + /** + * @see java.net.URLConnection#connect() + */ public void connect() throws IOException { // do nothing } + /** + * @see java.net.URLConnection#getContentType() + */ public String getContentType() { return "image/gif"; } + /** + * @see java.net.URLConnection#getContentLength() + */ public int getContentLength() { try { return inputStream.available(); diff --git a/src/java/org/apache/fop/image/ImageFactory.java b/src/java/org/apache/fop/image/ImageFactory.java index f7323a1a1..a99a4926d 100644 --- a/src/java/org/apache/fop/image/ImageFactory.java +++ b/src/java/org/apache/fop/image/ImageFactory.java @@ -63,7 +63,7 @@ public final class ImageFactory { ImageProvider jaiImage = new ImageProvider("JAIImage", "org.apache.fop.image.JAIImage"); ImageProvider jimiImage = new ImageProvider("JIMIImage", "org.apache.fop.image.JimiImage"); ImageProvider imageIoImage = new ImageProvider( - "ImageIOImage", "org.apache.fop.image.ImageIoImage"); + "ImageIOImage", "org.apache.fop.image.ImageIOImage"); ImageProvider gifImage = new ImageProvider("GIFImage", "org.apache.fop.image.GifImage"); ImageProvider jpegImage = new ImageProvider("JPEGImage", "org.apache.fop.image.JpegImage"); ImageProvider bmpImage = new ImageProvider("BMPImage", "org.apache.fop.image.BmpImage"); @@ -104,6 +104,7 @@ public final class ImageFactory { imt = new ImageMimeType("image/tiff"); imageMimeTypes.put(imt.getMimeType(), imt); imt.addProvider(tiffImage); + imt.addProvider(jaiImage); imt = new ImageMimeType("image/svg+xml"); imageMimeTypes.put(imt.getMimeType(), imt); diff --git a/src/java/org/apache/fop/image/JAIImage.java b/src/java/org/apache/fop/image/JAIImage.java index 636f37a51..8daaa9fc1 100644 --- a/src/java/org/apache/fop/image/JAIImage.java +++ b/src/java/org/apache/fop/image/JAIImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,26 +39,43 @@ import com.sun.media.jai.codec.FileCacheSeekableStream; */ public class JAIImage extends AbstractFopImage { - public JAIImage(FopImage.ImageInfo imgReader) { - super(imgReader); + /** + * Create a new JAI image. + * + * @param imgInfo the image info for this JAI image + */ + public JAIImage(FopImage.ImageInfo imgInfo) { + super(imgInfo); } + /** + * @see org.apache.fop.image.AbstractFopImage#loadDimensions() + */ + protected boolean loadDimensions() { + if (this.bitmaps == null) { + loadImage(); + } + return this.bitmaps != null; + } + + /** + * Loads the image from the inputstream + */ protected void loadImage() { + com.sun.media.jai.codec.FileCacheSeekableStream seekableInput = null; try { - com.sun.media.jai.codec.FileCacheSeekableStream seekableInput = - new FileCacheSeekableStream(inputStream); + seekableInput = new FileCacheSeekableStream(inputStream); RenderedOp imageOp = JAI.create("stream", seekableInput); - inputStream.close(); - inputStream = null; this.height = imageOp.getHeight(); this.width = imageOp.getWidth(); ColorModel cm = imageOp.getColorModel(); - this.bitsPerPixel = 8; - // this.bitsPerPixel = cm.getPixelSize(); - this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); - + //this.bitsPerPixel = 8; + this.bitsPerPixel = cm.getPixelSize(); + //this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + this.colorSpace = cm.getColorSpace(); + BufferedImage imageData = imageOp.getAsBufferedImage(); int[] tmpMap = imageData.getRGB(0, 0, this.width, this.height, null, 0, this.width); @@ -128,21 +145,29 @@ public class JAIImage extends AbstractFopImage { int r = (p >> 16) & 0xFF; int g = (p >> 8) & 0xFF; int b = (p) & 0xFF; - this.bitmaps[3 * (i * this.width + j)] = - (byte)(r & 0xFF); - this.bitmaps[3 * (i * this.width + j) + 1] = - (byte)(g & 0xFF); - this.bitmaps[3 * (i * this.width + j) + 2] = - (byte)(b & 0xFF); + this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF); + this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF); + this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF); } } } catch (Exception ex) { - /*throw new FopImageException("Error while loading image " - + "" + " : " - + ex.getClass() + " - " - + ex.getMessage()); - */} + log.error("Error while loading image (JAI): " + ex.getMessage(), ex); + } finally { + try { + inputStream.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + inputStream = null; + if (seekableInput != null) { + try { + seekableInput.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + } + } } } diff --git a/src/java/org/apache/fop/image/JimiImage.java b/src/java/org/apache/fop/image/JimiImage.java index 9688fbf01..e10024bea 100644 --- a/src/java/org/apache/fop/image/JimiImage.java +++ b/src/java/org/apache/fop/image/JimiImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,15 +37,18 @@ import com.sun.jimi.core.Jimi; */ public class JimiImage extends AbstractFopImage { - public JimiImage(FopImage.ImageInfo imgReader) { - super(imgReader); - try { - Class c = Class.forName("com.sun.jimi.core.Jimi"); - } catch (ClassNotFoundException e) { - //throw new FopImageException("Jimi image library not available"); - } + /** + * Create a new Jimi image. + * + * @param imgInfo the image info for this Jimi image + */ + public JimiImage(FopImage.ImageInfo imgInfo) { + super(imgInfo); } + /** + * @see org.apache.fop.image.AbstractFopImage#loadDimensions() + */ protected boolean loadDimensions() { if (this.bitmaps == null) { loadImage(); @@ -65,6 +68,9 @@ public class JimiImage extends AbstractFopImage { return this.bitmaps != null; } + /** + * Loads the image from the inputstream + */ protected void loadImage() { int[] tmpMap = null; try { @@ -80,9 +86,6 @@ public class JimiImage extends AbstractFopImage { this.height = consumer.getHeight(); this.width = consumer.getWidth(); - inputStream.close(); - inputStream = null; - try { tmpMap = consumer.getImage(); } catch (Exception ex) { @@ -149,9 +152,15 @@ public class JimiImage extends AbstractFopImage { this.isTransparent = false; } } catch (Throwable ex) { - log.error("Error while loading image " - + "", ex); + log.error("Error while loading image (Jimi): " + ex.getMessage(), ex); return; + } finally { + try { + inputStream.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + inputStream = null; } @@ -164,12 +173,9 @@ public class JimiImage extends AbstractFopImage { int r = (p >> 16) & 0xFF; int g = (p >> 8) & 0xFF; int b = (p) & 0xFF; - this.bitmaps[3 * (i * this.width + j)] = - (byte)(r & 0xFF); - this.bitmaps[3 * (i * this.width + j) + 1] = - (byte)(g & 0xFF); - this.bitmaps[3 * (i * this.width + j) + 2] = - (byte)(b & 0xFF); + this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF); + this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF); + this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF); } } } diff --git a/src/java/org/apache/fop/image/JpegImage.java b/src/java/org/apache/fop/image/JpegImage.java index a32e1f215..b3c8cb0bd 100644 --- a/src/java/org/apache/fop/image/JpegImage.java +++ b/src/java/org/apache/fop/image/JpegImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,13 +65,16 @@ public class JpegImage extends AbstractFopImage { while ((bytesRead = inputStream.read(readBuf)) != -1) { baos.write(readBuf, 0, bytesRead); } - inputStream.close(); - inputStream = null; } catch (java.io.IOException ex) { - log.error("Error while loading image " - + " : " + ex.getClass() - + " - " + ex.getMessage(), ex); + log.error("Error while loading image (Jpeg): " + ex.getMessage(), ex); return false; + } finally { + try { + inputStream.close(); + } catch (java.io.IOException ioe) { + // Ignore + } + inputStream = null; } this.bitmaps = baos.toByteArray(); @@ -163,10 +166,8 @@ public class JpegImage extends AbstractFopImage { byte[] align = new byte[((iccStream.size()) % 8) + 8]; try { iccStream.write(align); - } catch (Exception e) { - log.error("Error while loading image " - + " : " - + e.getMessage(), e); + } catch (Exception ex) { + log.error("Error while aligning ICC stream: " + ex.getMessage(), ex); return false; } try { diff --git a/src/java/org/apache/fop/image/PNGImage.java b/src/java/org/apache/fop/image/PNGImage.java index 4fd2e4acf..6235b9720 100644 --- a/src/java/org/apache/fop/image/PNGImage.java +++ b/src/java/org/apache/fop/image/PNGImage.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 The Apache Software Foundation + * Copyright 2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/java/org/apache/fop/image/TIFFImage.java b/src/java/org/apache/fop/image/TIFFImage.java index 9dc9b9c95..0f959c6f2 100644 --- a/src/java/org/apache/fop/image/TIFFImage.java +++ b/src/java/org/apache/fop/image/TIFFImage.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 The Apache Software Foundation + * Copyright 2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.apache.fop.image; +import java.awt.color.ColorSpace; import java.io.IOException; import org.apache.batik.ext.awt.image.codec.SeekableStream; @@ -31,6 +32,11 @@ import org.apache.batik.ext.awt.image.rendered.CachableRed; */ public class TIFFImage extends BatikImage { + private int compression = 0; + private int stripCount = 0; + private long stripOffset = 0; + private long stripLength = 0; + /** * Constructs a new BatikImage instance. * @param imgReader basic metadata for the image @@ -40,6 +46,22 @@ public class TIFFImage extends BatikImage { } /** + * The compression type set in the TIFF directory + * @return the TIFF compression type + */ + public int getCompression() { + return compression; + } + + /** + * The number of strips in the image + * @return the number of strips in the image + */ + public int getStripCount() { + return stripCount; + } + + /** * @see org.apache.fop.image.BatikImage#decodeImage(org.apache.batik.ext.awt.image.codec.SeekableStream) */ protected CachableRed decodeImage(SeekableStream stream) throws IOException { @@ -67,7 +89,73 @@ public class TIFFImage extends BatikImage { log.warn("Cannot determine bitmap resolution." + " Unimplemented resolution unit: " + resUnit); } + fld = dir.getField(TIFFImageDecoder.TIFF_COMPRESSION); + if (fld != null) { + compression = fld.getAsInt(0); + } + fld = dir.getField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE); + if (fld != null) { + bitsPerPixel = fld.getAsInt(0); + } + fld = dir.getField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP); + if (fld == null) { + stripCount = 1; + } else { + stripCount = (int)(dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_LENGTH) + / fld.getAsLong(0)); + } + stripOffset = dir.getField(TIFFImageDecoder.TIFF_STRIP_OFFSETS).getAsLong(0); + stripLength = dir.getField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS).getAsLong(0); + + if (this.bitsPerPixel == 1) { + this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY); + } return img; } - + + /** + * Load the original TIFF data. + * This loads only strip 1 of the original TIFF data. + * + * @return true if loaded false for any error + * @see org.apache.fop.image.AbstractFopImage#loadOriginalData() + */ + protected boolean loadOriginalData() { + if (loadDimensions()) { + byte[] readBuf = new byte[(int)stripLength]; + int bytesRead; + + try { + this.seekableInput.reset(); + this.seekableInput.skip(stripOffset); + bytesRead = seekableInput.read(readBuf); + if (bytesRead != stripLength) { + log.error("Error while loading image: length mismatch on read"); + return false; + } + + this.bitmaps = readBuf; + return true; + } catch (IOException ioe) { + log.error("Error while loading image strip 1 (TIFF): ", ioe); + return false; + } finally { + try { + this.seekableInput.close(); + } catch (IOException ioex) { + // ignore + } + try { + this.inputStream.close(); + } catch (IOException ioex) { + // ignore + } + this.seekableInput = null; + this.inputStream = null; + this.cr = null; + } + } + return false; + } + } diff --git a/src/java/org/apache/fop/pdf/BitmapImage.java b/src/java/org/apache/fop/pdf/BitmapImage.java index 5d1451929..6c8f61e5c 100644 --- a/src/java/org/apache/fop/pdf/BitmapImage.java +++ b/src/java/org/apache/fop/pdf/BitmapImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -196,19 +196,19 @@ public class BitmapImage implements PDFImage { } /** - * @see org.apache.fop.pdf.PDFImage#isDCT() - */ - public boolean isDCT() { - return false; - } - - /** * @see org.apache.fop.pdf.PDFImage#getFilterHint() */ public String getFilterHint() { return PDFFilterList.IMAGE_FILTER; } + /** + * @see org.apache.fop.pdf.PDFImage#getPDFFilter() + */ + public PDFFilter getPDFFilter() { + return null; + } + } diff --git a/src/java/org/apache/fop/pdf/CCFFilter.java b/src/java/org/apache/fop/pdf/CCFFilter.java new file mode 100644 index 000000000..ed8960ca0 --- /dev/null +++ b/src/java/org/apache/fop/pdf/CCFFilter.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.pdf; + +/** + * CCF Filter class. Right now it is just used as a dummy filter flag so + * we can write TIFF images to the PDF. The encode method just returns the + * data passed to it. In the future an actual CCITT Group 4 compression should be + * added to the encode method so other images can be compressed. + * + */ +public class CCFFilter extends NullFilter { + + private String decodeParms; + + /** + * @see org.apache.fop.pdf.PDFFilter#getName() + */ + public String getName() { + return "/CCITTFaxDecode"; + } + + /** + * @see org.apache.fop.pdf.PDFFilter#getDecodeParms() + */ + public String getDecodeParms() { + return this.decodeParms; + } + + /** + * Sets the CCF decoding parameters + * @param decodeParms The decoding parameters + */ + public void setDecodeParms(String decodeParms) { + this.decodeParms = decodeParms; + } + +} + diff --git a/src/java/org/apache/fop/pdf/PDFFilterList.java b/src/java/org/apache/fop/pdf/PDFFilterList.java index 499bafc06..4554ea6c6 100644 --- a/src/java/org/apache/fop/pdf/PDFFilterList.java +++ b/src/java/org/apache/fop/pdf/PDFFilterList.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,8 @@ public class PDFFilterList { public static final String IMAGE_FILTER = "image"; /** Key for the filter used for JPEG images */ public static final String JPEG_FILTER = "jpeg"; + /** Key for the filter used for TIFF images */ + public static final String TIFF_FILTER = "tiff"; /** Key for the filter used for fonts */ public static final String FONT_FILTER = "font"; @@ -131,15 +133,16 @@ public class PDFFilterList { } /** - * Checks the filter list for the DCT filter and adds it in the correct + * Checks the filter list for the filter and adds it in the correct * place if necessary. + * @param pdfFilter the filter to check / add */ - public void ensureDCTFilterInPlace() { + public void ensureFilterInPlace(PDFFilter pdfFilter) { if (this.filters.size() == 0) { - addFilter(new DCTFilter()); + addFilter(pdfFilter); } else { - if (!(this.filters.get(0) instanceof DCTFilter)) { - this.filters.add(0, new DCTFilter()); + if (!(this.filters.get(0).equals(pdfFilter))) { + this.filters.add(0, pdfFilter); } } } @@ -186,7 +189,9 @@ public class PDFFilterList { PDFFilter filter = (PDFFilter)filters.get(count); // place the names in our local vector in reverse order names.add(0, filter.getName()); - parms.add(0, filter.getDecodeParms()); + if (filter.getDecodeParms() != null) { + parms.add(0, filter.getDecodeParms()); + } } // now build up the filter entries for the dictionary @@ -197,20 +202,22 @@ public class PDFFilterList { } private String buildFilterEntries(List names) { - boolean needFilterEntry = false; + int filterCount = 0; StringBuffer sb = new StringBuffer(64); - sb.append("/Filter [ "); for (int i = 0; i < names.size(); i++) { final String name = (String)names.get(i); if (name.length() > 0) { - needFilterEntry = true; + filterCount++; sb.append(name); sb.append(" "); } } - if (needFilterEntry) { - sb.append("]"); - return sb.toString(); + if (filterCount > 0) { + if (filterCount > 1) { + return "/Filter [ " + sb.toString() + "]"; + } else { + return "/Filter " + sb.toString(); + } } else { return ""; } @@ -219,7 +226,7 @@ public class PDFFilterList { private String buildDecodeParms(List parms) { StringBuffer sb = new StringBuffer(); boolean needParmsEntry = false; - sb.append("/DecodeParms "); + sb.append("\n/DecodeParms "); if (parms.size() > 1) { sb.append("[ "); diff --git a/src/java/org/apache/fop/pdf/PDFImage.java b/src/java/org/apache/fop/pdf/PDFImage.java index 236426682..8be9c28a1 100644 --- a/src/java/org/apache/fop/pdf/PDFImage.java +++ b/src/java/org/apache/fop/pdf/PDFImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,13 +82,6 @@ public interface PDFImage { boolean isPS(); /** - * Check if this image is a DCT encoded image (for JPEG images). - * - * @return true if this is a DCT image - */ - boolean isDCT(); - - /** * Check if this image has a transparent color transparency. * * @return true if it has transparency @@ -116,6 +109,13 @@ public interface PDFImage { */ String getSoftMask(); + /** + * Get the PDF Filter to be applied to the image. + * + * @return the PDF Filter or null + */ + PDFFilter getPDFFilter(); + // get the image bytes, and bytes properties /** diff --git a/src/java/org/apache/fop/pdf/PDFXObject.java b/src/java/org/apache/fop/pdf/PDFXObject.java index 34c73cdaf..4d6e7f380 100644 --- a/src/java/org/apache/fop/pdf/PDFXObject.java +++ b/src/java/org/apache/fop/pdf/PDFXObject.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -174,8 +174,9 @@ public class PDFXObject extends AbstractPDFStream { * @see org.apache.fop.pdf.AbstractPDFStream#prepareImplicitFilters() */ protected void prepareImplicitFilters() { - if (pdfimage.isDCT()) { - getFilterList().ensureDCTFilterInPlace(); + PDFFilter pdfFilter = pdfimage.getPDFFilter(); + if (pdfFilter != null) { + getFilterList().ensureFilterInPlace(pdfFilter); } } diff --git a/src/java/org/apache/fop/render/pdf/FopPDFImage.java b/src/java/org/apache/fop/render/pdf/FopPDFImage.java index 3a80bf2de..e38c9f111 100644 --- a/src/java/org/apache/fop/render/pdf/FopPDFImage.java +++ b/src/java/org/apache/fop/render/pdf/FopPDFImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ /* $Id$ */ package org.apache.fop.render.pdf; - import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFImage; import org.apache.fop.pdf.PDFFilter; @@ -32,11 +31,13 @@ import org.apache.fop.pdf.BitmapImage; import org.apache.fop.image.FopImage; import org.apache.fop.image.JpegImage; import org.apache.fop.image.EPSImage; +import org.apache.fop.image.TIFFImage; import java.io.IOException; import java.io.OutputStream; import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; +import org.apache.fop.pdf.CCFFilter; /** * PDFImage implementation for the PDF renderer. @@ -49,6 +50,8 @@ public class FopPDFImage implements PDFImage { private String maskRef; private String softMaskRef; private boolean isPS = false; + private boolean isCCF = false; + private boolean isDCT = false; private String key; /** @@ -77,6 +80,7 @@ public class FopPDFImage implements PDFImage { if ("image/jpeg".equals(fopImage.getMimeType())) { pdfFilter = new DCTFilter(); pdfFilter.setApplied(true); + isDCT = true; JpegImage jpegimage = (JpegImage) fopImage; ICC_Profile prof = jpegimage.getICCProfile(); @@ -85,8 +89,35 @@ public class FopPDFImage implements PDFImage { pdfICCStream = doc.getFactory().makePDFICCStream(); pdfICCStream.setColorSpace(prof, pdfCS); } + } else if ("image/tiff".equals(fopImage.getMimeType()) + && fopImage instanceof TIFFImage) { + TIFFImage tiffImage = (TIFFImage) fopImage; + if (tiffImage.getStripCount() == 1) { + int comp = tiffImage.getCompression(); + if (comp == 1) { + // Nothing to do + } else if (comp == 3) { + pdfFilter = new CCFFilter(); + pdfFilter.setApplied(true); + isCCF = true; + } else if (comp == 4) { + pdfFilter = new CCFFilter(); + pdfFilter.setApplied(true); + ((CCFFilter)pdfFilter).setDecodeParms("<< /K -1 /Columns " + + tiffImage.getWidth() + " >>"); + isCCF = true; + } else if (comp == 6) { + pdfFilter = new DCTFilter(); + pdfFilter.setApplied(true); + isDCT = true; + } + } + } + if (isPS || isDCT || isCCF) { + fopImage.load(FopImage.ORIGINAL_DATA); + } else { + fopImage.load(FopImage.BITMAP); } - //Handle transparency mask if applicable if (fopImage.hasSoftMask()) { byte [] softMask = fopImage.getSoftMask(); @@ -103,20 +134,6 @@ public class FopPDFImage implements PDFImage { } /** - * @see org.apache.fop.pdf.PDFImage#isPS() - */ - public boolean isPS() { - return isPS; - } - - /** - * @see org.apache.fop.pdf.PDFImage#isDCT() - */ - public boolean isDCT() { - return fopImage.getMimeType().equals("image/jpeg"); - } - - /** * @see org.apache.fop.pdf.PDFImage#getWidth() */ public int getWidth() { @@ -176,6 +193,20 @@ public class FopPDFImage implements PDFImage { } /** + * @see org.apache.fop.pdf.PDFImage#isPS() + */ + public boolean isPS() { + return isPS; + } + + /** + * @see org.apache.fop.pdf.PDFImage#getPDFFilter() + */ + public PDFFilter getPDFFilter() { + return pdfFilter; + } + + /** * @see org.apache.fop.pdf.PDFImage#outputContents(OutputStream) */ public void outputContents(OutputStream out) throws IOException { @@ -268,10 +299,12 @@ public class FopPDFImage implements PDFImage { * @see org.apache.fop.pdf.PDFImage#getFilterHint() */ public String getFilterHint() { - if (isPS()) { + if (isPS) { return PDFFilterList.CONTENT_FILTER; - } else if (fopImage.getMimeType().equals("image/jpeg")) { + } else if (isDCT) { return PDFFilterList.JPEG_FILTER; + } else if (isCCF) { + return PDFFilterList.TIFF_FILTER; } else { return PDFFilterList.IMAGE_FILTER; } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index c8b188242..22e32d7dd 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -/* $Id: PDFRenderer.java,v 1.38 2004/04/07 14:24:17 cbowditch Exp $ */ +/* $Id$ */ package org.apache.fop.render.pdf; @@ -161,6 +161,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { */ protected PDFPage currentPage; + /** The current Transform */ protected AffineTransform currentBasicTransform; /** drawing state */ @@ -615,9 +616,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { setColor(uppercol, false, null); currentStream.add(x1 + " " + ym1 + " m " + x2 + " " + ym1 + " l S\n"); setColor(c, false, null); - currentStream.add(x1 + " " + (ym1 + h3) + " m " + x2 + " " + (ym1 + h3) + " l S\n"); + currentStream.add(x1 + " " + (ym1 + h3) + " m " + + x2 + " " + (ym1 + h3) + " l S\n"); setColor(lowercol, false, null); - currentStream.add(x1 + " " + (ym1 + h3 + h3) + " m " + x2 + " " + (ym1 + h3 + h3) + " l S\n"); + currentStream.add(x1 + " " + (ym1 + h3 + h3) + " m " + + x2 + " " + (ym1 + h3 + h3) + " l S\n"); } else { Color leftcol = lightenColor(c, -colFactor); Color rightcol = lightenColor(c, colFactor); @@ -627,9 +630,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { setColor(leftcol, false, null); currentStream.add(xm1 + " " + y1 + " m " + xm1 + " " + y2 + " l S\n"); setColor(c, false, null); - currentStream.add((xm1 + w3) + " " + y1 + " m " + (xm1 + w3) + " " + y2 + " l S\n"); + currentStream.add((xm1 + w3) + " " + y1 + " m " + + (xm1 + w3) + " " + y2 + " l S\n"); setColor(rightcol, false, null); - currentStream.add((xm1 + w3 + w3) + " " + y1 + " m " + (xm1 + w3 + w3) + " " + y2 + " l S\n"); + currentStream.add((xm1 + w3 + w3) + " " + y1 + " m " + + (xm1 + w3 + w3) + " " + y2 + " l S\n"); } break; } @@ -1398,16 +1403,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { renderDocument(doc, ns, pos); } else if ("image/eps".equals(mime)) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; - } FopPDFImage pdfimage = new FopPDFImage(fopimage, url); int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber(); fact.releaseImage(url, userAgent); - } else if ("image/jpeg".equals(mime)) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; - } + } else if ("image/jpeg".equals(mime) || "image/tiff".equals(mime)) { FopPDFImage pdfimage = new FopPDFImage(fopimage, url); int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber(); fact.releaseImage(url, userAgent); @@ -1417,9 +1416,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { placeImage((float) pos.getX() / 1000, (float) pos.getY() / 1000, w, h, xobj); } else { - if (!fopimage.load(FopImage.BITMAP)) { - return; - } FopPDFImage pdfimage = new FopPDFImage(fopimage, url); int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber(); fact.releaseImage(url, userAgent); diff --git a/test/layoutengine/testcases/external-graphic-tiff.xml b/test/layoutengine/testcases/external-graphic-tiff.xml index 1d93a5d19..1b38504b0 100644 --- a/test/layoutengine/testcases/external-graphic-tiff.xml +++ b/test/layoutengine/testcases/external-graphic-tiff.xml @@ -24,7 +24,7 @@ <fo> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"> <fo:layout-master-set> - <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in"> + <fo:simple-page-master master-name="normal" page-width="8in" page-height="8in"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> @@ -38,6 +38,10 @@ <fo:block> <fo:external-graphic src="../../resources/images/bgimg72dpi.tif"/>EOG </fo:block> + <fo:block>TIFF external-graphic (CCITT group 4 encoding)</fo:block> + <fo:block> + <fo:external-graphic src="../../resources/images/tiff_group4.tif"/>EOG + </fo:block> <fo:block>EOF</fo:block> </fo:flow> </fo:page-sequence> @@ -52,5 +56,9 @@ <eval expected="192000" xpath="//flow/block[4]/lineArea/viewport/@ipda"/> <eval expected="192000" xpath="//flow/block[4]/lineArea/viewport/@bpd"/> <eval expected="192000" xpath="//flow/block[4]/lineArea/viewport/@bpda"/> + <eval expected="550588" xpath="//flow/block[6]/lineArea/viewport/@ipd"/> + <eval expected="550588" xpath="//flow/block[6]/lineArea/viewport/@ipda"/> + <eval expected="66705" xpath="//flow/block[6]/lineArea/viewport/@bpd"/> + <eval expected="66705" xpath="//flow/block[6]/lineArea/viewport/@bpda"/> </checks> </testcase> diff --git a/test/resources/images/tiff_group4.tif b/test/resources/images/tiff_group4.tif Binary files differnew file mode 100644 index 000000000..5720e8f0c --- /dev/null +++ b/test/resources/images/tiff_group4.tif |