//Additional values
private String url;
- private FopImage fopimage;
+ private int intrinsicWidth;
+ private int intrinsicHeight;
/**
* Create a new External graphic node.
url = ImageFactory.getURL(getSrc());
FOUserAgent userAgent = getUserAgent();
ImageFactory fact = userAgent.getFactory().getImageFactory();
- fopimage = fact.getImage(url, userAgent);
+ FopImage fopimage = fact.getImage(url, userAgent);
if (fopimage == null) {
getLogger().error("Image not available: " + getSrc());
} else {
if (!fopimage.load(FopImage.DIMENSIONS)) {
getLogger().error("Cannot read image dimensions: " + getSrc());
}
+ this.intrinsicWidth = fopimage.getIntrinsicWidth();
+ this.intrinsicHeight = fopimage.getIntrinsicHeight();
}
//TODO Report to caller so he can decide to throw an exception
}
* @see org.apache.fop.fo.flow.AbstractGraphics#getIntrinsicWidth()
*/
public int getIntrinsicWidth() {
- if (fopimage != null) {
- return fopimage.getIntrinsicWidth();
- } else {
- return 0;
- }
+ return this.intrinsicWidth;
}
/**
* @see org.apache.fop.fo.flow.AbstractGraphics#getIntrinsicHeight()
*/
public int getIntrinsicHeight() {
- if (fopimage != null) {
- return fopimage.getIntrinsicHeight();
- } else {
- return 0;
- }
+ return this.intrinsicHeight;
}
}
// Java
import java.io.InputStream;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
+
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.URISpecification;
-
/**
* Create FopImage objects (with a configuration file - not yet implemented).
* @author Eric SCHAEFFER
imt = new ImageMimeType("image/png");
imageMimeTypes.put(imt.getMimeType(), imt);
+ //Image I/O is faster and more memory-efficient than own codec for PNG
+ imt.addProvider(imageIoImage);
imt.addProvider(pngImage);
imt = new ImageMimeType("image/tga");
imt = new ImageMimeType("image/tiff");
imageMimeTypes.put(imt.getMimeType(), imt);
- imt.addProvider(tiffImage);
- imt.addProvider(jaiImage);
+ imt.addProvider(tiffImage); //Slower but supports CCITT embedding
+ imt.addProvider(imageIoImage); //Fast but doesn't support CCITT embedding
+ imt.addProvider(jaiImage); //Fast but doesn't support CCITT embedding
imt = new ImageMimeType("image/svg+xml");
imageMimeTypes.put(imt.getMimeType(), imt);
private boolean collective;
private Map contextStore = Collections.synchronizedMap(new java.util.HashMap());
private Set invalid = null;
- private Map weakStore = null;
+ private Map refStore = null;
+ private ReferenceQueue refQueue = new ReferenceQueue();
public ContextImageCache(boolean col) {
collective = col;
if (collective) {
- weakStore = Collections.synchronizedMap(new java.util.WeakHashMap());
+ refStore = Collections.synchronizedMap(new java.util.HashMap());
invalid = Collections.synchronizedSet(new java.util.HashSet());
}
}
}
}
if (im == null) {
- im = (ImageLoader) weakStore.get(url);
+ Reference ref = (Reference)refStore.get(url);
+ if (ref != null) {
+ im = (ImageLoader) ref.get();
+ if (im == null) {
+ //Remove key if its value has been garbage collected
+ refStore.remove(url);
+ }
+ }
}
}
if (con != null) {
if (collective) {
ImageLoader im = con.getImage(url);
- weakStore.put(url, im);
+ refStore.put(url, wrapInReference(im, url));
}
con.releaseImage(url);
}
}
}
+ private Reference wrapInReference(Object obj, Object key) {
+ return new SoftReferenceWithKey(obj, key, refQueue);
+ }
+
+ private static class SoftReferenceWithKey extends SoftReference {
+
+ private Object key;
+
+ public SoftReferenceWithKey(Object referent, Object key, ReferenceQueue q) {
+ super(referent, q);
+ this.key = key;
+ }
+ }
+
public void removeContext(FOUserAgent context) {
Context con = (Context) contextStore.get(context);
if (con != null) {
if (collective) {
Map images = con.getImages();
- weakStore.putAll(images);
+ Iterator iter = images.entrySet().iterator();
+ while (iter.hasNext()) {
+ Entry entry = (Entry)iter.next();
+ refStore.put(entry.getKey(),
+ wrapInReference(entry.getValue(), entry.getKey()));
+ }
}
contextStore.remove(context);
}
+ //House-keeping (remove cleared references)
+ checkReferenceQueue();
+ }
+
+ /**
+ * Checks the reference queue if any references have been cleared and removes them from the
+ * cache.
+ */
+ private void checkReferenceQueue() {
+ SoftReferenceWithKey ref;
+ while ((ref = (SoftReferenceWithKey)refQueue.poll()) != null) {
+ refStore.remove(ref.key);
+ }
}
class Context {
/** @see org.apache.fop.image.ImageCache#clearAll() */
public void clearAll() {
- this.weakStore.clear();
+ this.refStore.clear();
this.invalid.clear();
//The context-sensitive caches are not cleared so there are no negative side-effects
//in a multi-threaded environment. Not that it's a good idea to use this method at