KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > codec > SimpleRenderedImage


1 /*
2
3    Copyright 2001,2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt.image.codec;
19
20 import java.awt.Point JavaDoc;
21 import java.awt.Rectangle JavaDoc;
22 import java.awt.image.ColorModel JavaDoc;
23 import java.awt.image.Raster JavaDoc;
24 import java.awt.image.RenderedImage JavaDoc;
25 import java.awt.image.SampleModel JavaDoc;
26 import java.awt.image.WritableRaster JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.Hashtable JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.Vector JavaDoc;
31
32 /**
33  * A simple class implemented the <code>RenderedImage</code>
34  * interface. Only the <code>getTile()</code> method needs to be
35  * implemented by subclasses. The instance variables must also be
36  * filled in properly.
37  *
38  * <p> Normally in JAI <code>PlanarImage</code> is used for this
39  * purpose, but in the interest of modularity the
40  * use of <code>PlanarImage</code> has been avoided.
41  */

42 public abstract class SimpleRenderedImage implements RenderedImage JavaDoc {
43
44     /** The X coordinate of the image's upper-left pixel. */
45     protected int minX;
46     
47     /** The Y coordinate of the image's upper-left pixel. */
48     protected int minY;
49     
50     /** The image's width in pixels. */
51     protected int width;
52     
53     /** The image's height in pixels. */
54     protected int height;
55     
56     /** The width of a tile. */
57     protected int tileWidth;
58     
59     /** The height of a tile. */
60     protected int tileHeight;
61
62     /** The X coordinate of the upper-left pixel of tile (0, 0). */
63     protected int tileGridXOffset = 0;
64     
65     /** The Y coordinate of the upper-left pixel of tile (0, 0). */
66     protected int tileGridYOffset = 0;
67     
68     /** The image's SampleModel. */
69     protected SampleModel JavaDoc sampleModel = null;
70     
71     /** The image's ColorModel. */
72     protected ColorModel JavaDoc colorModel = null;
73     
74     /** The image's sources, stored in a Vector. */
75     protected Vector JavaDoc sources = new Vector JavaDoc();
76
77     /** A Hashtable containing the image properties. */
78     protected Hashtable JavaDoc properties = new Hashtable JavaDoc();
79
80     public SimpleRenderedImage() {}
81
82     /** Returns the X coordinate of the leftmost column of the image. */
83     public int getMinX() {
84         return minX;
85     }
86
87     /**
88      * Returns the X coordinate of the column immediatetely to the
89      * right of the rightmost column of the image. getMaxX() is
90      * implemented in terms of getMinX() and getWidth() and so does
91      * not need to be implemented by subclasses.
92      */

93     public final int getMaxX() {
94         return getMinX() + getWidth();
95     }
96
97     /** Returns the X coordinate of the uppermost row of the image. */
98     public int getMinY() {
99         return minY;
100     }
101
102     /**
103      * Returns the Y coordinate of the row immediately below the
104      * bottom row of the image. getMaxY() is implemented in terms of
105      * getMinY() and getHeight() and so does not need to be
106      * implemented by subclasses.
107      */

108     public final int getMaxY() {
109         return getMinY() + getHeight();
110     }
111
112     /** Returns the width of the image. */
113     public int getWidth() {
114         return width;
115     }
116
117     /** Returns the height of the image. */
118     public int getHeight() {
119         return height;
120     }
121     
122     /** Returns a Rectangle indicating the image bounds. */
123     public Rectangle JavaDoc getBounds() {
124         return new Rectangle JavaDoc(getMinX(), getMinY(),
125                              getWidth(), getHeight());
126     }
127     
128     /** Returns the width of a tile. */
129     public int getTileWidth() {
130         return tileWidth;
131     }
132
133     /** Returns the height of a tile. */
134     public int getTileHeight() {
135         return tileHeight;
136     }
137
138     /**
139      * Returns the X coordinate of the upper-left pixel of tile (0, 0).
140      */

141     public int getTileGridXOffset() {
142         return tileGridXOffset;
143     }
144
145     /**
146      * Returns the Y coordinate of the upper-left pixel of tile (0, 0).
147      */

148     public int getTileGridYOffset() {
149         return tileGridYOffset;
150     }
151
152     /**
153      * Returns the horizontal index of the leftmost column of tiles.
154      * getMinTileX() is implemented in terms of getMinX()
155      * and so does not need to be implemented by subclasses.
156      */

157     public int getMinTileX() {
158         return XToTileX(getMinX());
159     }
160
161     /**
162      * Returns the horizontal index of the rightmost column of tiles.
163      * getMaxTileX() is implemented in terms of getMaxX()
164      * and so does not need to be implemented by subclasses.
165      */

166     public int getMaxTileX() {
167         return XToTileX(getMaxX() - 1);
168     }
169
170     /**
171      * Returns the number of tiles along the tile grid in the
172      * horizontal direction. getNumXTiles() is implemented in terms
173      * of getMinTileX() and getMaxTileX() and so does not need to be
174      * implemented by subclasses.
175      */

176     public int getNumXTiles() {
177         return getMaxTileX() - getMinTileX() + 1;
178     }
179     
180     /**
181      * Returns the vertical index of the uppermost row of tiles. getMinTileY()
182      * is implemented in terms of getMinY() and so does not need to be
183      * implemented by subclasses.
184      */

185     public int getMinTileY() {
186         return YToTileY(getMinY());
187     }
188
189     /**
190      * Returns the vertical index of the bottom row of tiles. getMaxTileY()
191      * is implemented in terms of getMaxY() and so does not need to
192      * be implemented by subclasses.
193      */

194     public int getMaxTileY() {
195         return YToTileY(getMaxY() - 1);
196     }
197
198     /**
199      * Returns the number of tiles along the tile grid in the vertical
200      * direction. getNumYTiles() is implemented in terms
201      * of getMinTileY() and getMaxTileY() and so does not need to be
202      * implemented by subclasses.
203      */

204     public int getNumYTiles() {
205         return getMaxTileY() - getMinTileY() + 1;
206     }
207
208     /** Returns the SampleModel of the image. */
209     public SampleModel JavaDoc getSampleModel() {
210         return sampleModel;
211     }
212
213     /** Returns the ColorModel of the image. */
214     public ColorModel JavaDoc getColorModel() {
215         return colorModel;
216     }
217
218     /**
219      * Gets a property from the property set of this image. If the
220      * property name is not recognized,
221      * <code>java.awt.Image.UndefinedProperty</code> will be returned.
222      *
223      * @param name the name of the property to get, as a
224      * <code>String</code>. @return a reference to the property
225      * <code>Object</code>, or the value
226      * <code>java.awt.Image.UndefinedProperty.</code>
227      */

228     public Object JavaDoc getProperty(String JavaDoc name) {
229         name = name.toLowerCase();
230         return properties.get(name);
231     }
232     
233     /**
234      * Returns a list of the properties recognized by this image. If
235      * no properties are available, <code>null</code> will be
236      * returned.
237      *
238      * @return an array of <code>String</code>s representing valid
239      * property names.
240      */

241     public String JavaDoc[] getPropertyNames() {
242         String JavaDoc[] names = new String JavaDoc[properties.size()];
243         int index = 0;
244
245         Enumeration JavaDoc e = properties.keys();
246         while (e.hasMoreElements()) {
247             String JavaDoc name = (String JavaDoc)e.nextElement();
248             names[index++] = name;
249         }
250         
251         return names;
252     }
253
254     /**
255      * Returns an array of <code>String</code>s recognized as names by
256      * this property source that begin with the supplied prefix. If
257      * no property names match, <code>null</code> will be returned.
258      * The comparison is done in a case-independent manner.
259      *
260      * <p> The default implementation calls
261      * <code>getPropertyNames()</code> and searches the list of names
262      * for matches.
263      *
264      * @return an array of <code>String</code>s giving the valid
265      * property names.
266      */

267     public String JavaDoc[] getPropertyNames(String JavaDoc prefix) {
268         String JavaDoc propertyNames[] = getPropertyNames();
269         if (propertyNames == null) {
270             return null;
271         }
272
273         prefix = prefix.toLowerCase();
274
275         Vector JavaDoc names = new Vector JavaDoc();
276         for (int i = 0; i < propertyNames.length; i++) {
277             if (propertyNames[i].startsWith(prefix)) {
278                 names.addElement(propertyNames[i]);
279             }
280         }
281
282         if (names.size() == 0) {
283             return null;
284         }
285
286         // Copy the strings from the Vector over to a String array.
287
String JavaDoc prefixNames[] = new String JavaDoc[names.size()];
288         int count = 0;
289         for (Iterator JavaDoc it = names.iterator(); it.hasNext(); ) {
290             prefixNames[count++] = (String JavaDoc)it.next();
291         }
292
293         return prefixNames;
294     }
295
296     // Utility methods.
297

298     /**
299      * Converts a pixel's X coordinate into a horizontal tile index
300      * relative to a given tile grid layout specified by its X offset
301      * and tile width.
302      */

303     public static int XToTileX(int x, int tileGridXOffset, int tileWidth) {
304         x -= tileGridXOffset;
305         if (x < 0) {
306             x += 1 - tileWidth; // Force round to -infinity
307
}
308         return x/tileWidth;
309     }
310
311     /**
312      * Converts a pixel's Y coordinate into a vertical tile index
313      * relative to a given tile grid layout specified by its Y offset
314      * and tile height.
315      */

316     public static int YToTileY(int y, int tileGridYOffset, int tileHeight) {
317         y -= tileGridYOffset;
318         if (y < 0) {
319             y += 1 - tileHeight; // Force round to -infinity
320
}
321         return y/tileHeight;
322     }
323
324     /**
325      * Converts a pixel's X coordinate into a horizontal tile index.
326      * This is a convenience method. No attempt is made to detect
327      * out-of-range coordinates.
328      *
329      * @param x the X coordinate of a pixel.
330      * @return the X index of the tile containing the pixel.
331      */

332     public int XToTileX(int x) {
333         return XToTileX(x, getTileGridXOffset(), getTileWidth());
334     }
335
336     /**
337      * Converts a pixel's Y coordinate into a vertical tile index.
338      * This is a convenience method. No attempt is made to detect
339      * out-of-range coordinates.
340      *
341      * @param y the Y coordinate of a pixel.
342      * @return the Y index of the tile containing the pixel.
343      */

344     public int YToTileY(int y) {
345         return YToTileY(y, getTileGridYOffset(), getTileHeight());
346     }
347
348     /**
349      * Converts a horizontal tile index into the X coordinate of its
350      * upper left pixel relative to a given tile grid layout specified
351      * by its X offset and tile width.
352      */

353     public static int tileXToX(int tx, int tileGridXOffset, int tileWidth) {
354         return tx*tileWidth + tileGridXOffset;
355     }
356
357     /**
358      * Converts a vertical tile index into the Y coordinate of
359      * its upper left pixel relative to a given tile grid layout
360      * specified by its Y offset and tile height.
361      */

362     public static int tileYToY(int ty, int tileGridYOffset, int tileHeight) {
363         return ty*tileHeight + tileGridYOffset;
364     }
365
366     /**
367      * Converts a horizontal tile index into the X coordinate of its
368      * upper left pixel. This is a convenience method. No attempt is made
369      * to detect out-of-range indices.
370      *
371      * @param tx the horizontal index of a tile.
372      * @return the X coordinate of the tile's upper left pixel.
373      */

374     public int tileXToX(int tx) {
375         return tx*tileWidth + tileGridXOffset;
376     }
377
378     /**
379      * Converts a vertical tile index into the Y coordinate of its
380      * upper left pixel. This is a convenience method. No attempt is made
381      * to detect out-of-range indices.
382      *
383      * @param ty the vertical index of a tile.
384      * @return the Y coordinate of the tile's upper left pixel.
385      */

386     public int tileYToY(int ty) {
387         return ty*tileHeight + tileGridYOffset;
388     }
389
390     public Vector JavaDoc getSources() {
391         return null;
392     }
393
394     /**
395      * Returns the entire image in a single Raster. For images with
396      * multiple tiles this will require making a copy.
397      *
398      * <p> The returned Raster is semantically a copy. This means
399      * that updates to the source image will not be reflected in the
400      * returned Raster. For non-writable (immutable) source images,
401      * the returned value may be a reference to the image's internal
402      * data. The returned Raster should be considered non-writable;
403      * any attempt to alter its pixel data (such as by casting it to
404      * WritableRaster or obtaining and modifying its DataBuffer) may
405      * result in undefined behavior. The copyData method should be
406      * used if the returned Raster is to be modified.
407      *
408      * @return a Raster containing a copy of this image's data.
409      */

410     public Raster JavaDoc getData() {
411         Rectangle JavaDoc rect = new Rectangle JavaDoc(getMinX(), getMinY(),
412                                        getWidth(), getHeight());
413         return getData(rect);
414     }
415
416     /**
417      * Returns an arbitrary rectangular region of the RenderedImage
418      * in a Raster. The rectangle of interest will be clipped against
419      * the image bounds.
420      *
421      * <p> The returned Raster is semantically a copy. This means
422      * that updates to the source image will not be reflected in the
423      * returned Raster. For non-writable (immutable) source images,
424      * the returned value may be a reference to the image's internal
425      * data. The returned Raster should be considered non-writable;
426      * any attempt to alter its pixel data (such as by casting it to
427      * WritableRaster or obtaining and modifying its DataBuffer) may
428      * result in undefined behavior. The copyData method should be
429      * used if the returned Raster is to be modified.
430      *
431      * @param bounds the region of the RenderedImage to be returned.
432      */

433     public Raster JavaDoc getData(Rectangle JavaDoc bounds) {
434         int startX = XToTileX(bounds.x);
435         int startY = YToTileY(bounds.y);
436         int endX = XToTileX(bounds.x + bounds.width - 1);
437         int endY = YToTileY(bounds.y + bounds.height - 1);
438         Raster JavaDoc tile;
439
440         if ((startX == endX) && (startY == endY)) {
441             tile = getTile(startX, startY);
442             return tile.createChild(bounds.x, bounds.y,
443                                     bounds.width, bounds.height,
444                                     bounds.x, bounds.y, null);
445         } else {
446             // Create a WritableRaster of the desired size
447
SampleModel JavaDoc sm =
448                 sampleModel.createCompatibleSampleModel(bounds.width,
449                                                        bounds.height);
450
451             // Translate it
452
WritableRaster JavaDoc dest =
453                 Raster.createWritableRaster(sm, bounds.getLocation());
454
455             for (int j = startY; j <= endY; j++) {
456                 for (int i = startX; i <= endX; i++) {
457                     tile = getTile(i, j);
458                     Rectangle JavaDoc intersectRect =
459                         bounds.intersection(tile.getBounds());
460                     Raster JavaDoc liveRaster = tile.createChild(intersectRect.x,
461                                                          intersectRect.y,
462                                                          intersectRect.width,
463                                                          intersectRect.height,
464                                                          intersectRect.x,
465                                                          intersectRect.y,
466                                                          null);
467                     dest.setDataElements(0, 0, liveRaster);
468                 }
469             }
470             return dest;
471         }
472     }
473
474     /**
475      * Copies an arbitrary rectangular region of the RenderedImage
476      * into a caller-supplied WritableRaster. The region to be
477      * computed is determined by clipping the bounds of the supplied
478      * WritableRaster against the bounds of the image. The supplied
479      * WritableRaster must have a SampleModel that is compatible with
480      * that of the image.
481      *
482      * <p> If the raster argument is null, the entire image will
483      * be copied into a newly-created WritableRaster with a SampleModel
484      * that is compatible with that of the image.
485      *
486      * @param dest a WritableRaster to hold the returned portion of
487      * the image.
488      * @return a reference to the supplied WritableRaster, or to a
489      * new WritableRaster if the supplied one was null.
490      */

491     public WritableRaster JavaDoc copyData(WritableRaster JavaDoc dest) {
492         Rectangle JavaDoc bounds;
493         Raster JavaDoc tile;
494                     
495         if (dest == null) {
496             bounds = getBounds();
497             Point JavaDoc p = new Point JavaDoc(minX, minY);
498             /* A SampleModel to hold the entire image. */
499             SampleModel JavaDoc sm = sampleModel.createCompatibleSampleModel(
500                                          width, height);
501             dest = Raster.createWritableRaster(sm, p);
502         } else {
503             bounds = dest.getBounds();
504         }
505         
506         int startX = XToTileX(bounds.x);
507         int startY = YToTileY(bounds.y);
508         int endX = XToTileX(bounds.x + bounds.width - 1);
509         int endY = YToTileY(bounds.y + bounds.height - 1);
510             
511         for (int j = startY; j <= endY; j++) {
512             for (int i = startX; i <= endX; i++) {
513                 tile = getTile(i, j);
514                 Rectangle JavaDoc intersectRect =
515                     bounds.intersection(tile.getBounds());
516                 Raster JavaDoc liveRaster = tile.createChild(intersectRect.x,
517                                                      intersectRect.y,
518                                                      intersectRect.width,
519                                                      intersectRect.height,
520                                                      intersectRect.x,
521                                                      intersectRect.y,
522                                                      null);
523
524                 /*
525                  * WritableRaster.setDataElements takes into account of
526                  * inRaster's minX and minY and add these to x and y. Since
527                  * liveRaster has the origin at the correct location, the
528                  * following call should not again give these coordinates in
529                  * places of x and y.
530                  */

531                 dest.setDataElements(0, 0, liveRaster);
532             }
533         }
534         return dest;
535     }
536 }
537
Popular Tags