Index: src/org/apache/fop/image/BmpImage.java
===================================================================
RCS file: /home/cvspublic/xml-fop/src/org/apache/fop/image/Attic/BmpImage.java,v
retrieving revision 1.3.2.1
diff -u -w -w -u -r1.3.2.1 BmpImage.java
--- src/org/apache/fop/image/BmpImage.java 25 Feb 2003 13:38:22 -0000 1.3.2.1
+++ src/org/apache/fop/image/BmpImage.java 5 Apr 2005 15:41:23 -0000
@@ -51,11 +51,10 @@
package org.apache.fop.image;
// Java
-import java.net.URL;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
-// FOP
import org.apache.fop.datatypes.ColorSpace;
import org.apache.fop.image.analyser.ImageReader;
@@ -81,6 +80,10 @@
int[] headermap = new int[54];
int filepos = 0;
InputStream file = null;
+ // BUGFIX: do always close the inputstream (the garbage collector may do this
+ // too late when handling pdfs with many images!!)
+ try
+ {
byte palette[] = null;
try {
file = this.m_href.openStream();
@@ -235,6 +238,21 @@
j++;
}
}
+ }
+ finally
+ {
+ if (file!=null)
+ {
+ try
+ {
+ file.close();
+ }
+ catch(IOException e)
+ {
+ // can be ignored
+ }
+ }
+ }
// This seems really strange to me, but I noticed that JimiImage hardcodes
// m_bitsPerPixel to 8. If I do not do this Acrobat is unable to read the resultant PDF,
Index: src/org/apache/fop/image/FopImageFactory.java
===================================================================
RCS file: /home/cvspublic/xml-fop/src/org/apache/fop/image/Attic/FopImageFactory.java,v
retrieving revision 1.25.2.13
diff -u -w -w -u -r1.25.2.13 FopImageFactory.java
--- src/org/apache/fop/image/FopImageFactory.java 10 May 2003 18:29:58 -0000 1.25.2.13
+++ src/org/apache/fop/image/FopImageFactory.java 5 Apr 2005 15:41:24 -0000
@@ -51,28 +51,111 @@
package org.apache.fop.image;
// FOP
-import org.apache.fop.image.analyser.ImageReaderFactory;
-import org.apache.fop.image.analyser.ImageReader;
-import org.apache.fop.configuration.Configuration;
-import org.apache.fop.messaging.MessageHandler;
-
-// Java
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
-import java.net.MalformedURLException;
import java.lang.reflect.Constructor;
-import java.util.Map;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.fop.configuration.Configuration;
+import org.apache.fop.image.analyser.ImageReader;
+import org.apache.fop.image.analyser.ImageReaderFactory;
+import org.apache.fop.messaging.MessageHandler;
/**
* create FopImage objects (with a configuration file - not yet implemented).
+ *
+ * This image cache does now support automatic clearing of the cache, if there
+ * are too many images inside the cache. This behaviour can be controlled by
+ * the following fop configuration parameters (stored e.g. with
+ * org.apache.fop.configuration.Configuration.put(param,value)
):
+ *
+ *
+ * - imagecache_max: the maximum count of image elements. If the cache exeeds
+ * this size, it will be shrinked to the imagecache_min size.
+ *
+ *
+ * Default: 100
+ *
+ *
+ *
+ * - imagecache_max_size: the maximum size in bytes of the image cache. If the cache exeeds
+ * this size, it will be shrinked to the imagecache_min_size size.
+ *
+ *
+ * Default: 2097152 (2Mbyte)
+ *
+ *
+ *
+ * -
+ *
- imagecache_min: the minimum count of image elements. If the cache exeeds
+ * the max size, it will be shrinked to this size.
+ *
+ *
+ * Default: 25
+ *
+ *
+ *
+ * - imagecache_min_size: the minimum size in bytes of the image cache. If the cache exeeds
+ * the max size, it will be shrinked to the imagecache_min_size size.
+ *
+ *
+ * Default: 1048576 (1MByte)
+ *
+ *
+ *
+ * -
+ *
- imagecache_debug: (true|false) if true, detailled cache information will be logged.
+ *
+ *
+ * Default: false
+ *
+ *
+ *
+ *
+ * Note (1): if the max parameter is 0, the cache will not be cleared automatically
+ * (same behaviour as before).
+ *
+ *
+ * Note (2): the parameters must be stored as strings, because the Configuration object
+ * returns Integer object as -1!
+ *
* @author Eric SCHAEFFER
*/
public class FopImageFactory {
+
// prevent instantiation
- protected FopImageFactory() {}
+ protected FopImageFactory() {};
+
+ // contains the sorted cache entries
+ private static SortedSet m_imageCache = new TreeSet();
+
+ // contains the keys which point to the cache entries
+ private static HashMap m_urlMap=new HashMap();
+
+ /**
+ * The minimum cache size.
+ */
+ private static int DEFAULT_MIN=25;
- private static Map m_urlMap = new java.util.HashMap();
+ /**
+ * The maximum cache size.
+ */
+ private static int DEFAULT_MAX=100;
+
+ /**
+ * The mimimum image cache size in bytes.
+ */
+ private static long DEFAULT_MIN_SIZE=1048576;
+
+ /**
+ * The maximum image cache size in bytes.
+ */
+ private static long DEFAULT_MAX_SIZE=2097152;
/**
* The class name of the generic image handler.
@@ -112,9 +195,44 @@
}
// check if already created
- FopImage imageObject = (FopImage)m_urlMap.get(href);
- if (imageObject != null)
- return imageObject;
+ // use the image cache
+ ImageCacheEntry cacheentry=(ImageCacheEntry)m_urlMap.get(href);
+ FopImage image=null;
+ if (cacheentry != null)
+ {
+ m_imageCache.remove(cacheentry);
+
+ // this increases the modification count
+ image=cacheentry.getFopimage();
+
+ // re-sort (this can be inside this method, because it is synchronized
+ m_imageCache.add(cacheentry);
+
+ return image;
+ }
+
+ String _debug=org.apache.fop.configuration.Configuration.getStringValue("imagecache_debug");
+ if (_debug==null)
+ _debug="false";
+ boolean imagecache_debug=_debug.toLowerCase().startsWith("t");
+ if (imagecache_debug)
+ {
+ StringBuffer sb=new StringBuffer();
+ for (Iterator iterator=m_imageCache.iterator();iterator.hasNext();)
+ {
+ ImageCacheEntry ce=(ImageCacheEntry)iterator.next();
+
+ sb.append(" * "+ce.getUrl()+"\n");
+ sb.append(" - image size: "+ce.getImageSize()+"\n");
+ sb.append(" - last access: "+new java.util.Date(ce.getLastaccessTime())+"\n");
+ }
+
+ if (cacheentry==null)
+ MessageHandler.log("Adding new image: "+href);
+ else
+ MessageHandler.log("Found image: "+href);
+ MessageHandler.log("\n"+sb.toString()+"\n");
+ }
try {
// try url as complete first, this can cause
@@ -264,7 +382,62 @@
+ "class " + imageClass.getName()
+ " doesn't implement org.apache.fop.image.FopImage interface");
}
- m_urlMap.put(href, imageInstance);
+
+ // BUGFIX: this checks the map size (otherwise we will always get out of memory
+ // errors or too man open files errors when building large pdf files)
+ cacheentry=new ImageCacheEntry((FopImage)imageInstance,href);
+
+ int min=org.apache.fop.configuration.Configuration.getIntValue("imagecache_min");
+ if (min<0)
+ min=DEFAULT_MIN;
+ int max=org.apache.fop.configuration.Configuration.getIntValue("imagecache_max");
+ if (max<0)
+ max=DEFAULT_MAX;
+ long max_size=org.apache.fop.configuration.Configuration.getIntValue("imagecache_max_size");
+ if (max_size<0)
+ max_size=DEFAULT_MAX_SIZE;
+ long min_size=org.apache.fop.configuration.Configuration.getIntValue("imagecache_min_size");
+ if (min_size<0)
+ min_size=DEFAULT_MIN_SIZE;
+
+ // get image cache size
+ long cachesize=0;
+ for (Iterator it=m_imageCache.iterator();it.hasNext();)
+ {
+ ImageCacheEntry ce=(ImageCacheEntry)it.next();
+ if (ce.getImageSize()>=0)
+ cachesize+=ce.getImageSize();
+ }
+
+ if ((max!=0) &&
+ ((m_imageCache.size()>max) || (max_size<=cachesize)))
+ {
+ if (m_imageCache.size()>max)
+ MessageHandler.log("clearing fop image cache (from "+m_imageCache.size()+" elements to "+min+" elements)");
+ else
+ MessageHandler.log("clearing fop image cache (from "+cachesize+" byte to "+min_size+" byte)");
+
+ // cache size exceeded, shrink to min
+ do
+ {
+ ImageCacheEntry ce=(ImageCacheEntry)m_imageCache.first();
+
+ if (imagecache_debug)
+ MessageHandler.log(" * deleting "+ce.getUrl()+" ("+ce.getImageSize()+" byte)");
+
+ cachesize-=ce.getImageSize();
+ m_imageCache.remove(ce);
+ m_urlMap.remove(ce.getUrl());
+
+ } while((m_imageCache.size()>min) || (min_size<=cachesize));
+ }
+
+ // add new entry to sorted map
+ m_imageCache.add(cacheentry);
+
+ // and add to url map too
+ m_urlMap.put(href,cacheentry);
+
return (FopImage)imageInstance;
}
@@ -297,6 +470,16 @@
*/
public static synchronized void resetCache() {
m_urlMap.clear();
- }
+ m_imageCache.clear();
}
+ /**
+ * Returns the cached image count.
+ *
+ * @return the cached image count.
+ */
+ public static int getCacheSize()
+ {
+ return m_urlMap.size();
+ }
+}
\ No newline at end of file
Index: src/org/apache/fop/image/JAIImage.java
===================================================================
RCS file: /home/cvspublic/xml-fop/src/org/apache/fop/image/Attic/JAIImage.java,v
retrieving revision 1.2.2.1
diff -u -w -w -u -r1.2.2.1 JAIImage.java
--- src/org/apache/fop/image/JAIImage.java 25 Feb 2003 13:38:22 -0000 1.2.2.1
+++ src/org/apache/fop/image/JAIImage.java 5 Apr 2005 15:41:24 -0000
@@ -51,23 +51,21 @@
package org.apache.fop.image;
// Java
-import java.net.URL;
-import java.io.InputStream;
-
-// AWT
+import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
-import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
-// JAI
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
-// Sun codec
-import com.sun.media.jai.codec.FileCacheSeekableStream;
-// FOP
+
import org.apache.fop.datatypes.ColorSpace;
-import org.apache.fop.pdf.PDFColor;
import org.apache.fop.image.analyser.ImageReader;
+import org.apache.fop.pdf.PDFColor;
+
+import com.sun.media.jai.codec.FileCacheSeekableStream;
/**
* FopImage object using JAI.
@@ -87,7 +85,13 @@
protected void loadImage() throws FopImageException {
try {
- InputStream inputStream = this.m_href.openStream();
+ // BUGFIX: do always close the inputstream (the garbage collector may do this
+ // too late when handling pdfs with many images!!)
+ InputStream inputStream=null;
+ try
+ {
+ inputStream = this.m_href.openStream();
+
/*
* BufferedInputStream inputStream = this.m_imageReader.getInputStream();
* inputStream.reset();
@@ -180,6 +184,21 @@
& 0xFF);
}
}
+ }
+ finally
+ {
+ if (inputStream!=null)
+ {
+ try
+ {
+ inputStream.close();
+ }
+ catch(IOException e)
+ {
+ // can be ignored
+ }
+ }
+ }
} catch (Exception ex) {
throw new FopImageException("Error while loading image "
Index: src/org/apache/fop/image/JimiImage.java
===================================================================
RCS file: /home/cvspublic/xml-fop/src/org/apache/fop/image/Attic/JimiImage.java,v
retrieving revision 1.8.2.3
diff -u -w -w -u -r1.8.2.3 JimiImage.java
--- src/org/apache/fop/image/JimiImage.java 21 Sep 2003 11:50:53 -0000 1.8.2.3
+++ src/org/apache/fop/image/JimiImage.java 5 Apr 2005 15:41:24 -0000
@@ -51,18 +51,18 @@
package org.apache.fop.image;
// Java
-import java.net.URL;
-import java.awt.image.ImageProducer;
import java.awt.image.ColorModel;
+import java.awt.image.ImageProducer;
import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
-// Jimi
-import com.sun.jimi.core.Jimi;
-
-// FOP
import org.apache.fop.datatypes.ColorSpace;
-import org.apache.fop.pdf.PDFColor;
import org.apache.fop.image.analyser.ImageReader;
+import org.apache.fop.pdf.PDFColor;
+
+import com.sun.jimi.core.Jimi;
/**
* FopImage object for several images types, using Jimi.
@@ -94,7 +94,13 @@
protected void loadImage() throws FopImageException {
int[] tmpMap = null;
try {
- ImageProducer ip = Jimi.getImageProducer(this.m_href.openStream(),
+ // BUGFIX: do always close the inputstream (the garbage collector may do this
+ // too late when handling pdfs with many images!!)
+ InputStream inputStream=null;
+ try
+ {
+ inputStream=this.m_href.openStream();
+ ImageProducer ip = Jimi.getImageProducer(inputStream,
Jimi.SYNCHRONOUS
| Jimi.IN_MEMORY);
FopImageConsumer consumer = new FopImageConsumer(ip);
@@ -170,6 +176,21 @@
} else {
this.m_isTransparent = false;
}
+ }
+ finally
+ {
+ if (inputStream!=null)
+ {
+ try
+ {
+ inputStream.close();
+ }
+ catch(IOException e)
+ {
+ // can be ignored
+ }
+ }
+ }
} catch (Exception ex) {
throw new FopImageException("Error while loading image "
+ this.m_href.toString() + " : "
Index: src/org/apache/fop/image/JpegImage.java
===================================================================
RCS file: /home/cvspublic/xml-fop/src/org/apache/fop/image/Attic/JpegImage.java,v
retrieving revision 1.1.2.4
diff -u -w -w -u -r1.1.2.4 JpegImage.java
--- src/org/apache/fop/image/JpegImage.java 27 Jul 2003 22:10:41 -0000 1.1.2.4
+++ src/org/apache/fop/image/JpegImage.java 5 Apr 2005 15:41:25 -0000
@@ -51,14 +51,14 @@
package org.apache.fop.image;
// Java
-import java.net.URL;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
+import java.net.URL;
-// FOP
import org.apache.fop.datatypes.ColorSpace;
-import org.apache.fop.pdf.DCTFilter;
import org.apache.fop.image.analyser.ImageReader;
+import org.apache.fop.pdf.DCTFilter;
/**
* FopImage object for JPEG images, Using Java native classes.
@@ -85,7 +85,7 @@
protected void loadImage() throws FopImageException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayOutputStream iccStream = new ByteArrayOutputStream();
- InputStream inStream;
+ InputStream inStream=null;
this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_UNKNOWN);
byte[] readBuf = new byte[4096];
int bytes_read;
@@ -95,6 +95,11 @@
this.m_compressionType = new DCTFilter();
this.m_compressionType.setApplied(true);
+ // BUGFIX: do always close the inputstream (the garbage collector may do this
+ // too late when handling pdfs with many images!!)
+ try
+ {
+
try {
inStream = this.m_href.openStream();
@@ -227,6 +232,22 @@
throw new FopImageException( "\n1 Error while loading image " +
this.m_href.toString() + " : JpegImage - Invalid JPEG Header.");
}
+ }
+ finally
+ {
+ if (inStream!=null)
+ {
+ try
+ {
+ inStream.close();
+ }
+ catch(IOException e)
+ {
+ // can be ignored
+ }
+ }
+ }
+
if (iccStream.size() > 0) {
byte[] align = new byte[((iccStream.size()) % 8) + 8];
try {iccStream.write(align);} catch (Exception e) {
Index: src/org/apache/fop/image/TiffImage.java
===================================================================
RCS file: /home/cvspublic/xml-fop/src/org/apache/fop/image/Attic/TiffImage.java,v
retrieving revision 1.1.2.2
diff -u -w -w -u -r1.1.2.2 TiffImage.java
--- src/org/apache/fop/image/TiffImage.java 25 Feb 2003 13:38:22 -0000 1.1.2.2
+++ src/org/apache/fop/image/TiffImage.java 5 Apr 2005 15:41:25 -0000
@@ -52,6 +52,7 @@
// Java
import java.net.URL;
+import java.io.IOException;
import java.io.InputStream;
// Sun codec
@@ -83,7 +84,13 @@
protected void loadImage() throws FopImageException {
try {
- InputStream inputStream = this.m_href.openStream();
+ InputStream inputStream = null;
+ // BUGFIX: do always close the inputstream (the garbage collector may do this
+ // too late when handling pdfs with many images!!)
+ try
+ {
+ inputStream=this.m_href.openStream();
+
/*
* BufferedInputStream inputStream = this.m_imageReader.getInputStream();
* inputStream.reset();
@@ -185,6 +192,21 @@
}
this.m_bitmaps = readBuf;
+ }
+ finally
+ {
+ if (inputStream!=null)
+ {
+ try
+ {
+ inputStream.close();
+ }
+ catch(IOException e)
+ {
+ // can be ignored
+ }
+ }
+ }
} catch (FopImageException fie) {
org.apache.fop.messaging.MessageHandler.logln("Reverting to TIFF image handling through JAI: "
+ fie.getMessage());