001: /*
002: * $RCSfile: RenderableCRIF.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:41 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.RenderingHints;
015: import java.awt.geom.Rectangle2D;
016: import java.awt.image.RenderedImage;
017: import java.awt.image.renderable.RenderContext;
018: import java.awt.image.renderable.ParameterBlock;
019: import java.awt.image.renderable.RenderableImage;
020: import java.lang.ref.SoftReference;
021: import java.util.Hashtable;
022: import java.util.Vector;
023: import javax.media.jai.CRIFImpl;
024: import javax.media.jai.ImageMIPMap;
025: import javax.media.jai.MultiResolutionRenderableImage;
026: import javax.media.jai.RenderedOp;
027:
028: /**
029: * A <code>CRIF</code> supporting the "Renderable" operation in the
030: * renderable image layers.
031: *
032: * @see javax.media.jai.operator.RenderableDescriptor
033: *
034: *
035: * @since 1.0
036: */
037: public class RenderableCRIF extends CRIFImpl {
038: /** Cache of SoftReferences to the MultiResolutionRenderableImages. */
039: private Hashtable mresTable = null;
040:
041: /** Derives a hash key for this ParameterBlock. */
042: private static final Object getKey(ParameterBlock paramBlock) {
043: // Initialize the key string.
044: String key = new String();
045:
046: // Add the hash code of the source to the key.
047: key += String.valueOf(paramBlock.getRenderedSource(0)
048: .hashCode());
049:
050: // Add the RenderedOp parameter to the key.
051: key += getKey((RenderedOp) paramBlock.getObjectParameter(0));
052:
053: // Add the numerical parameters to the key.
054: key += String.valueOf(paramBlock.getIntParameter(1));
055: key += String.valueOf(paramBlock.getFloatParameter(2));
056: key += String.valueOf(paramBlock.getFloatParameter(3));
057: key += String.valueOf(paramBlock.getFloatParameter(4));
058:
059: return key;
060: }
061:
062: /** Derives a hash key string for this RenderedOp. */
063: private static final String getKey(RenderedOp op) {
064: // Initialize the key string to the RenderedOp hash code.
065: String key = new String(String.valueOf(op.hashCode()));
066:
067: // Get the ParameterBlock
068: ParameterBlock pb = op.getParameterBlock();
069:
070: // Add the sources.
071: int numSources = pb.getNumSources();
072: for (int s = 0; s < numSources; s++) {
073: RenderedImage src = pb.getRenderedSource(s);
074:
075: // If the source is a node recurse up the chain.
076: if (src instanceof RenderedOp) {
077: key += getKey((RenderedOp) src);
078: } else {
079: key += String.valueOf(src.hashCode());
080: }
081: }
082:
083: // Add the parameters.
084: int numParameters = pb.getNumParameters();
085: for (int p = 0; p < numParameters; p++) {
086: // Use toString() instead of hashCode() here because the
087: // majority of parameters are numerical.
088: key += pb.getObjectParameter(p).toString();
089: }
090:
091: return key;
092: }
093:
094: /** Constructor. */
095: public RenderableCRIF() {
096: }
097:
098: /**
099: * Creates a RenderableImage pyramid from the source and parameters.
100: * If the down sampler operation chain does not decrease both the
101: * width and height at a given level an IllegalArgumentException will
102: * be thrown.
103: *
104: * @param paramBlock The ParameterBlock containing a single RenderedImage
105: * source and parameters sufficient to create an image pyramid.
106: */
107: private RenderableImage createRenderable(ParameterBlock paramBlock) {
108: // Create the Hashtable "just in time".
109: if (mresTable == null) {
110: mresTable = new Hashtable();
111: }
112:
113: // Check for a SoftReference hashed on a ParameterBlock-derived key.
114: Object key = getKey(paramBlock);
115: SoftReference ref = (SoftReference) mresTable.get(key);
116:
117: // Retrieve the image from the SoftReference if possible.
118: RenderableImage mres = null;
119: if (ref != null && (mres = (RenderableImage) ref.get()) == null) {
120: // null referent: remove the ParameterBlock key from the Hashtable.
121: mresTable.remove(key);
122: }
123:
124: // Derive the image if necessary.
125: if (mres == null) {
126: // Retrieve the source and parameters.
127: RenderedImage source = paramBlock.getRenderedSource(0);
128: RenderedOp downSampler = (RenderedOp) paramBlock
129: .getObjectParameter(0);
130: int maxLowResDim = paramBlock.getIntParameter(1);
131: float minX = paramBlock.getFloatParameter(2);
132: float minY = paramBlock.getFloatParameter(3);
133: float height = paramBlock.getFloatParameter(4);
134:
135: // Create an image pyramid.
136: ImageMIPMap pyramid = new ImageMIPMap(source, downSampler);
137:
138: // Create a Vector of RenderedImages from the pyramid.
139: Vector sourceVector = new Vector();
140: RenderedImage currentImage = pyramid.getCurrentImage();
141: sourceVector.add(currentImage);
142: while (currentImage.getWidth() > maxLowResDim
143: || currentImage.getHeight() > maxLowResDim) {
144: RenderedImage nextImage = pyramid.getDownImage();
145: if (nextImage.getWidth() >= currentImage.getWidth()
146: || nextImage.getHeight() >= currentImage
147: .getHeight()) {
148: throw new IllegalArgumentException(JaiI18N
149: .getString("RenderableCRIF0"));
150: }
151: sourceVector.add(nextImage);
152: currentImage = nextImage;
153: }
154:
155: // Create a RenderableImage
156: mres = new MultiResolutionRenderableImage(sourceVector,
157: minX, minY, height);
158:
159: // Store a SoftReference to the RenderableImage in the Hashtable.
160: mresTable.put(key, new SoftReference(mres));
161: }
162:
163: return mres;
164: }
165:
166: /**
167: * Returns the source RenderedImage.
168: * This method satisfies the implementation of RIF.
169: */
170: public RenderedImage create(ParameterBlock paramBlock,
171: RenderingHints renderHints) {
172: return paramBlock.getRenderedSource(0);
173: }
174:
175: /**
176: * Creates a new instance of <code>AffineOpImage</code>
177: * in the renderable layer. This method satisfies the
178: * implementation of CRIF.
179: */
180: public RenderedImage create(RenderContext renderContext,
181: ParameterBlock paramBlock) {
182: RenderableImage mres = createRenderable(paramBlock);
183:
184: return mres.createRendering(renderContext);
185: }
186:
187: /**
188: * Gets the output bounding box in rendering-independent space.
189: * This method satisfies the implementation of CRIF.
190: */
191: public Rectangle2D getBounds2D(ParameterBlock paramBlock) {
192: RenderableImage mres = createRenderable(paramBlock);
193:
194: return new Rectangle2D.Float(mres.getMinX(), mres.getMinY(),
195: mres.getWidth(), mres.getHeight());
196: }
197:
198: }
|