|
1 /* |
|
2 * Portions Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 /* ******************************************************************** |
|
27 ********************************************************************** |
|
28 ********************************************************************** |
|
29 *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** |
|
30 *** As an unpublished work pursuant to Title 17 of the United *** |
|
31 *** States Code. All rights reserved. *** |
|
32 ********************************************************************** |
|
33 ********************************************************************** |
|
34 **********************************************************************/ |
|
35 |
|
36 package java.awt.image.renderable; |
|
37 import java.awt.geom.AffineTransform; |
|
38 import java.awt.geom.Rectangle2D; |
|
39 import java.awt.image.RenderedImage; |
|
40 import java.awt.RenderingHints; |
|
41 import java.util.Hashtable; |
|
42 import java.util.Vector; |
|
43 |
|
44 /** |
|
45 * This class handles the renderable aspects of an operation with help |
|
46 * from its associated instance of a ContextualRenderedImageFactory. |
|
47 */ |
|
48 public class RenderableImageOp implements RenderableImage { |
|
49 |
|
50 /** A ParameterBlock containing source and parameters. */ |
|
51 ParameterBlock paramBlock; |
|
52 |
|
53 /** The associated ContextualRenderedImageFactory. */ |
|
54 ContextualRenderedImageFactory myCRIF; |
|
55 |
|
56 /** The bounding box of the results of this RenderableImageOp. */ |
|
57 Rectangle2D boundingBox; |
|
58 |
|
59 |
|
60 /** |
|
61 * Constructs a RenderedImageOp given a |
|
62 * ContextualRenderedImageFactory object, and |
|
63 * a ParameterBlock containing RenderableImage sources and other |
|
64 * parameters. Any RenderedImage sources referenced by the |
|
65 * ParameterBlock will be ignored. |
|
66 * |
|
67 * @param CRIF a ContextualRenderedImageFactory object |
|
68 * @param paramBlock a ParameterBlock containing this operation's source |
|
69 * images and other parameters necessary for the operation |
|
70 * to run. |
|
71 */ |
|
72 public RenderableImageOp(ContextualRenderedImageFactory CRIF, |
|
73 ParameterBlock paramBlock) { |
|
74 this.myCRIF = CRIF; |
|
75 this.paramBlock = (ParameterBlock) paramBlock.clone(); |
|
76 } |
|
77 |
|
78 /** |
|
79 * Returns a vector of RenderableImages that are the sources of |
|
80 * image data for this RenderableImage. Note that this method may |
|
81 * return an empty vector, to indicate that the image has no sources, |
|
82 * or null, to indicate that no information is available. |
|
83 * |
|
84 * @return a (possibly empty) Vector of RenderableImages, or null. |
|
85 */ |
|
86 public Vector<RenderableImage> getSources() { |
|
87 return getRenderableSources(); |
|
88 } |
|
89 |
|
90 private Vector getRenderableSources() { |
|
91 Vector sources = null; |
|
92 |
|
93 if (paramBlock.getNumSources() > 0) { |
|
94 sources = new Vector(); |
|
95 int i = 0; |
|
96 while (i < paramBlock.getNumSources()) { |
|
97 Object o = paramBlock.getSource(i); |
|
98 if (o instanceof RenderableImage) { |
|
99 sources.add((RenderableImage)o); |
|
100 i++; |
|
101 } else { |
|
102 break; |
|
103 } |
|
104 } |
|
105 } |
|
106 return sources; |
|
107 } |
|
108 |
|
109 /** |
|
110 * Gets a property from the property set of this image. |
|
111 * If the property name is not recognized, java.awt.Image.UndefinedProperty |
|
112 * will be returned. |
|
113 * |
|
114 * @param name the name of the property to get, as a String. |
|
115 * @return a reference to the property Object, or the value |
|
116 * java.awt.Image.UndefinedProperty. |
|
117 */ |
|
118 public Object getProperty(String name) { |
|
119 return myCRIF.getProperty(paramBlock, name); |
|
120 } |
|
121 |
|
122 /** |
|
123 * Return a list of names recognized by getProperty. |
|
124 * @return a list of property names. |
|
125 */ |
|
126 public String[] getPropertyNames() { |
|
127 return myCRIF.getPropertyNames(); |
|
128 } |
|
129 |
|
130 /** |
|
131 * Returns true if successive renderings (that is, calls to |
|
132 * createRendering() or createScaledRendering()) with the same arguments |
|
133 * may produce different results. This method may be used to |
|
134 * determine whether an existing rendering may be cached and |
|
135 * reused. The CRIF's isDynamic method will be called. |
|
136 * @return <code>true</code> if successive renderings with the |
|
137 * same arguments might produce different results; |
|
138 * <code>false</code> otherwise. |
|
139 */ |
|
140 public boolean isDynamic() { |
|
141 return myCRIF.isDynamic(); |
|
142 } |
|
143 |
|
144 /** |
|
145 * Gets the width in user coordinate space. By convention, the |
|
146 * usual width of a RenderableImage is equal to the image's aspect |
|
147 * ratio (width divided by height). |
|
148 * |
|
149 * @return the width of the image in user coordinates. |
|
150 */ |
|
151 public float getWidth() { |
|
152 if (boundingBox == null) { |
|
153 boundingBox = myCRIF.getBounds2D(paramBlock); |
|
154 } |
|
155 return (float)boundingBox.getWidth(); |
|
156 } |
|
157 |
|
158 /** |
|
159 * Gets the height in user coordinate space. By convention, the |
|
160 * usual height of a RenderedImage is equal to 1.0F. |
|
161 * |
|
162 * @return the height of the image in user coordinates. |
|
163 */ |
|
164 public float getHeight() { |
|
165 if (boundingBox == null) { |
|
166 boundingBox = myCRIF.getBounds2D(paramBlock); |
|
167 } |
|
168 return (float)boundingBox.getHeight(); |
|
169 } |
|
170 |
|
171 /** |
|
172 * Gets the minimum X coordinate of the rendering-independent image data. |
|
173 */ |
|
174 public float getMinX() { |
|
175 if (boundingBox == null) { |
|
176 boundingBox = myCRIF.getBounds2D(paramBlock); |
|
177 } |
|
178 return (float)boundingBox.getMinX(); |
|
179 } |
|
180 |
|
181 /** |
|
182 * Gets the minimum Y coordinate of the rendering-independent image data. |
|
183 */ |
|
184 public float getMinY() { |
|
185 if (boundingBox == null) { |
|
186 boundingBox = myCRIF.getBounds2D(paramBlock); |
|
187 } |
|
188 return (float)boundingBox.getMinY(); |
|
189 } |
|
190 |
|
191 /** |
|
192 * Change the current ParameterBlock of the operation, allowing |
|
193 * editing of image rendering chains. The effects of such a |
|
194 * change will be visible when a new rendering is created from |
|
195 * this RenderableImageOp or any dependent RenderableImageOp. |
|
196 * |
|
197 * @param paramBlock the new ParameterBlock. |
|
198 * @return the old ParameterBlock. |
|
199 * @see #getParameterBlock |
|
200 */ |
|
201 public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { |
|
202 ParameterBlock oldParamBlock = this.paramBlock; |
|
203 this.paramBlock = (ParameterBlock)paramBlock.clone(); |
|
204 return oldParamBlock; |
|
205 } |
|
206 |
|
207 /** |
|
208 * Returns a reference to the current parameter block. |
|
209 * @return the <code>ParameterBlock</code> of this |
|
210 * <code>RenderableImageOp</code>. |
|
211 * @see #setParameterBlock(ParameterBlock) |
|
212 */ |
|
213 public ParameterBlock getParameterBlock() { |
|
214 return paramBlock; |
|
215 } |
|
216 |
|
217 /** |
|
218 * Creates a RenderedImage instance of this image with width w, and |
|
219 * height h in pixels. The RenderContext is built automatically |
|
220 * with an appropriate usr2dev transform and an area of interest |
|
221 * of the full image. All the rendering hints come from hints |
|
222 * passed in. |
|
223 * |
|
224 * <p> If w == 0, it will be taken to equal |
|
225 * Math.round(h*(getWidth()/getHeight())). |
|
226 * Similarly, if h == 0, it will be taken to equal |
|
227 * Math.round(w*(getHeight()/getWidth())). One of |
|
228 * w or h must be non-zero or else an IllegalArgumentException |
|
229 * will be thrown. |
|
230 * |
|
231 * <p> The created RenderedImage may have a property identified |
|
232 * by the String HINTS_OBSERVED to indicate which RenderingHints |
|
233 * were used to create the image. In addition any RenderedImages |
|
234 * that are obtained via the getSources() method on the created |
|
235 * RenderedImage may have such a property. |
|
236 * |
|
237 * @param w the width of rendered image in pixels, or 0. |
|
238 * @param h the height of rendered image in pixels, or 0. |
|
239 * @param hints a RenderingHints object containg hints. |
|
240 * @return a RenderedImage containing the rendered data. |
|
241 */ |
|
242 public RenderedImage createScaledRendering(int w, int h, |
|
243 RenderingHints hints) { |
|
244 // DSR -- code to try to get a unit scale |
|
245 double sx = (double)w/getWidth(); |
|
246 double sy = (double)h/getHeight(); |
|
247 if (Math.abs(sx/sy - 1.0) < 0.01) { |
|
248 sx = sy; |
|
249 } |
|
250 AffineTransform usr2dev = AffineTransform.getScaleInstance(sx, sy); |
|
251 RenderContext newRC = new RenderContext(usr2dev, hints); |
|
252 return createRendering(newRC); |
|
253 } |
|
254 |
|
255 /** |
|
256 * Gets a RenderedImage instance of this image with a default |
|
257 * width and height in pixels. The RenderContext is built |
|
258 * automatically with an appropriate usr2dev transform and an area |
|
259 * of interest of the full image. All the rendering hints come |
|
260 * from hints passed in. Implementors of this interface must be |
|
261 * sure that there is a defined default width and height. |
|
262 * |
|
263 * @return a RenderedImage containing the rendered data. |
|
264 */ |
|
265 public RenderedImage createDefaultRendering() { |
|
266 AffineTransform usr2dev = new AffineTransform(); // Identity |
|
267 RenderContext newRC = new RenderContext(usr2dev); |
|
268 return createRendering(newRC); |
|
269 } |
|
270 |
|
271 /** |
|
272 * Creates a RenderedImage which represents this |
|
273 * RenderableImageOp (including its Renderable sources) rendered |
|
274 * according to the given RenderContext. |
|
275 * |
|
276 * <p> This method supports chaining of either Renderable or |
|
277 * RenderedImage operations. If sources in |
|
278 * the ParameterBlock used to construct the RenderableImageOp are |
|
279 * RenderableImages, then a three step process is followed: |
|
280 * |
|
281 * <ol> |
|
282 * <li> mapRenderContext() is called on the associated CRIF for |
|
283 * each RenderableImage source; |
|
284 * <li> createRendering() is called on each of the RenderableImage sources |
|
285 * using the backwards-mapped RenderContexts obtained in step 1, |
|
286 * resulting in a rendering of each source; |
|
287 * <li> ContextualRenderedImageFactory.create() is called |
|
288 * with a new ParameterBlock containing the parameters of |
|
289 * the RenderableImageOp and the RenderedImages that were created by the |
|
290 * createRendering() calls. |
|
291 * </ol> |
|
292 * |
|
293 * <p> If the elements of the source Vector of |
|
294 * the ParameterBlock used to construct the RenderableImageOp are |
|
295 * instances of RenderedImage, then the CRIF.create() method is |
|
296 * called immediately using the original ParameterBlock. |
|
297 * This provides a basis case for the recursion. |
|
298 * |
|
299 * <p> The created RenderedImage may have a property identified |
|
300 * by the String HINTS_OBSERVED to indicate which RenderingHints |
|
301 * (from the RenderContext) were used to create the image. |
|
302 * In addition any RenderedImages |
|
303 * that are obtained via the getSources() method on the created |
|
304 * RenderedImage may have such a property. |
|
305 * |
|
306 * @param renderContext The RenderContext to use to perform the rendering. |
|
307 * @return a RenderedImage containing the desired output image. |
|
308 */ |
|
309 public RenderedImage createRendering(RenderContext renderContext) { |
|
310 RenderedImage image = null; |
|
311 RenderContext rcOut = null; |
|
312 |
|
313 // Clone the original ParameterBlock; if the ParameterBlock |
|
314 // contains RenderableImage sources, they will be replaced by |
|
315 // RenderedImages. |
|
316 ParameterBlock renderedParamBlock = (ParameterBlock)paramBlock.clone(); |
|
317 Vector sources = getRenderableSources(); |
|
318 |
|
319 try { |
|
320 // This assumes that if there is no renderable source, that there |
|
321 // is a rendered source in paramBlock |
|
322 |
|
323 if (sources != null) { |
|
324 Vector renderedSources = new Vector(); |
|
325 for (int i = 0; i < sources.size(); i++) { |
|
326 rcOut = myCRIF.mapRenderContext(i, renderContext, |
|
327 paramBlock, this); |
|
328 RenderedImage rdrdImage = |
|
329 ((RenderableImage)sources.elementAt(i)).createRendering(rcOut); |
|
330 if (rdrdImage == null) { |
|
331 return null; |
|
332 } |
|
333 |
|
334 // Add this rendered image to the ParameterBlock's |
|
335 // list of RenderedImages. |
|
336 renderedSources.addElement(rdrdImage); |
|
337 } |
|
338 |
|
339 if (renderedSources.size() > 0) { |
|
340 renderedParamBlock.setSources(renderedSources); |
|
341 } |
|
342 } |
|
343 |
|
344 return myCRIF.create(renderContext, renderedParamBlock); |
|
345 } catch (ArrayIndexOutOfBoundsException e) { |
|
346 // This should never happen |
|
347 return null; |
|
348 } |
|
349 } |
|
350 } |