Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: non_com/media/jai/codec/SimpleRenderedImage.java


1   /*
2    *  Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
3    *
4    *  Redistribution and use in source and binary forms, with or without
5    *  modification, are permitted provided that the following conditions are met:
6    *
7    *  -Redistributions of source code must retain the above copyright notice, this
8    *  list of conditions and the following disclaimer.
9    *
10   *  -Redistribution in binary form must reproduct the above copyright notice,
11   *  this list of conditions and the following disclaimer in the documentation
12   *  and/or other materials provided with the distribution.
13   *
14   *  Neither the name of Sun Microsystems, Inc. or the names of contributors may
15   *  be used to endorse or promote products derived from this software without
16   *  specific prior written permission.
17   *
18   *  This software is provided "AS IS," without a warranty of any kind. ALL
19   *  EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
20   *  IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
21   *  NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
22   *  LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
23   *  OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
24   *  LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
25   *  INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
26   *  CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
27   *  OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
28   *  POSSIBILITY OF SUCH DAMAGES.
29   *
30   *  You acknowledge that Software is not designed,licensed or intended for use in
31   *  the design, construction, operation or maintenance of any nuclear facility.
32   */
33  package non_com.media.jai.codec;
34  
35  import java.awt.Point;
36  import java.awt.Rectangle;
37  import java.awt.image.ColorModel;
38  import java.awt.image.Raster;
39  import java.awt.image.RenderedImage;
40  import java.awt.image.SampleModel;
41  import java.awt.image.WritableRaster;
42  import java.util.Enumeration;
43  import java.util.Hashtable;
44  import java.util.Iterator;
45  import java.util.Vector;
46  import non_com.media.jai.RasterFactory;
47  
48  /**
49   *  A simple class implemented the <code>RenderedImage</code> interface. Only
50   *  the <code>getTile()</code> method needs to be implemented by subclasses. The
51   *  instance variables must also be filled in properly. <p>
52   *
53   *  Normally in JAI <code>PlanarImage</code> is used for this purpose, but in
54   *  the interest of making <code>com.sun.media.jai.codec</code> and <code>com.sun.media.jai.codecimpl</code>
55   *  be as modular as possible the use of <code>PlanarImage</code> has been
56   *  avoided.
57   *
58   */
59  public abstract class SimpleRenderedImage implements RenderedImage {
60  
61    /**
62     *  The X coordinate of the image's upper-left pixel.
63     */
64    protected int minX;
65  
66    /**
67     *  The Y coordinate of the image's upper-left pixel.
68     */
69    protected int minY;
70  
71    /**
72     *  The image's width in pixels.
73     */
74    protected int width;
75  
76    /**
77     *  The image's height in pixels.
78     */
79    protected int height;
80  
81    /**
82     *  The width of a tile.
83     */
84    protected int tileWidth;
85  
86    /**
87     *  The height of a tile.
88     */
89    protected int tileHeight;
90  
91    /**
92     *  The X coordinate of the upper-left pixel of tile (0, 0).
93     */
94    protected int tileGridXOffset = 0;
95  
96    /**
97     *  The Y coordinate of the upper-left pixel of tile (0, 0).
98     */
99    protected int tileGridYOffset = 0;
100 
101   /**
102    *  The image's SampleModel.
103    */
104   protected SampleModel sampleModel = null;
105 
106   /**
107    *  The image's ColorModel.
108    */
109   protected ColorModel colorModel = null;
110 
111   /**
112    *  The image's sources, stored in a Vector.
113    */
114   protected Vector sources = new Vector();
115 
116   /**
117    *  A Hashtable containing the image properties.
118    */
119   protected Hashtable properties = new Hashtable();
120 
121 
122   /**
123    *  Constructor for the SimpleRenderedImage object
124    */
125   public SimpleRenderedImage() {
126   }
127 
128 
129   // Utility methods.
130 
131   /**
132    *  Converts a pixel's X coordinate into a horizontal tile index relative to a
133    *  given tile grid layout specified by its X offset and tile width.
134    *
135    * @param  x                Description of Parameter
136    * @param  tileGridXOffset  Description of Parameter
137    * @param  tileWidth        Description of Parameter
138    * @return                  Description of the Returned Value
139    */
140   public static int XToTileX(int x, int tileGridXOffset, int tileWidth) {
141     x -= tileGridXOffset;
142     if (x < 0) {
143       x += 1 - tileWidth;
144       // Force round to -infinity
145     }
146     return x / tileWidth;
147   }
148 
149 
150   /**
151    *  Converts a pixel's Y coordinate into a vertical tile index relative to a
152    *  given tile grid layout specified by its Y offset and tile height.
153    *
154    * @param  y                Description of Parameter
155    * @param  tileGridYOffset  Description of Parameter
156    * @param  tileHeight       Description of Parameter
157    * @return                  Description of the Returned Value
158    */
159   public static int YToTileY(int y, int tileGridYOffset, int tileHeight) {
160     y -= tileGridYOffset;
161     if (y < 0) {
162       y += 1 - tileHeight;
163       // Force round to -infinity
164     }
165     return y / tileHeight;
166   }
167 
168 
169   /**
170    *  Converts a horizontal tile index into the X coordinate of its upper left
171    *  pixel relative to a given tile grid layout specified by its X offset and
172    *  tile width.
173    *
174    * @param  tx               Description of Parameter
175    * @param  tileGridXOffset  Description of Parameter
176    * @param  tileWidth        Description of Parameter
177    * @return                  Description of the Returned Value
178    */
179   public static int tileXToX(int tx, int tileGridXOffset, int tileWidth) {
180     return tx * tileWidth + tileGridXOffset;
181   }
182 
183 
184   /**
185    *  Converts a vertical tile index into the Y coordinate of its upper left
186    *  pixel relative to a given tile grid layout specified by its Y offset and
187    *  tile height.
188    *
189    * @param  ty               Description of Parameter
190    * @param  tileGridYOffset  Description of Parameter
191    * @param  tileHeight       Description of Parameter
192    * @return                  Description of the Returned Value
193    */
194   public static int tileYToY(int ty, int tileGridYOffset, int tileHeight) {
195     return ty * tileHeight + tileGridYOffset;
196   }
197 
198 
199   /**
200    *  Returns the X coordinate of the leftmost column of the image.
201    *
202    * @return    The MinX value
203    */
204   public int getMinX() {
205     return minX;
206   }
207 
208 
209   /**
210    *  Returns the X coordinate of the column immediatetely to the right of the
211    *  rightmost column of the image. getMaxX() is implemented in terms of
212    *  getMinX() and getWidth() and so does not need to be implemented by
213    *  subclasses.
214    *
215    * @return    The MaxX value
216    */
217   public final int getMaxX() {
218     return getMinX() + getWidth();
219   }
220 
221 
222   /**
223    *  Returns the X coordinate of the uppermost row of the image.
224    *
225    * @return    The MinY value
226    */
227   public int getMinY() {
228     return minY;
229   }
230 
231 
232   /**
233    *  Returns the Y coordinate of the row immediately below the bottom row of
234    *  the image. getMaxY() is implemented in terms of getMinY() and getHeight()
235    *  and so does not need to be implemented by subclasses.
236    *
237    * @return    The MaxY value
238    */
239   public final int getMaxY() {
240     return getMinY() + getHeight();
241   }
242 
243 
244   /**
245    *  Returns the width of the image.
246    *
247    * @return    The Width value
248    */
249   public int getWidth() {
250     return width;
251   }
252 
253 
254   /**
255    *  Returns the height of the image.
256    *
257    * @return    The Height value
258    */
259   public int getHeight() {
260     return height;
261   }
262 
263 
264   /**
265    *  Returns a Rectangle indicating the image bounds.
266    *
267    * @return    The Bounds value
268    */
269   public Rectangle getBounds() {
270     return new Rectangle(getMinX(), getMinY(),
271         getWidth(), getHeight());
272   }
273 
274 
275   /**
276    *  Returns the width of a tile.
277    *
278    * @return    The TileWidth value
279    */
280   public int getTileWidth() {
281     return tileWidth;
282   }
283 
284 
285   /**
286    *  Returns the height of a tile.
287    *
288    * @return    The TileHeight value
289    */
290   public int getTileHeight() {
291     return tileHeight;
292   }
293 
294 
295   /**
296    *  Returns the X coordinate of the upper-left pixel of tile (0, 0).
297    *
298    * @return    The TileGridXOffset value
299    */
300   public int getTileGridXOffset() {
301     return tileGridXOffset;
302   }
303 
304 
305   /**
306    *  Returns the Y coordinate of the upper-left pixel of tile (0, 0).
307    *
308    * @return    The TileGridYOffset value
309    */
310   public int getTileGridYOffset() {
311     return tileGridYOffset;
312   }
313 
314 
315   /**
316    *  Returns the horizontal index of the leftmost column of tiles.
317    *  getMinTileX() is implemented in terms of getMinX() and so does not need to
318    *  be implemented by subclasses.
319    *
320    * @return    The MinTileX value
321    */
322   public int getMinTileX() {
323     return XToTileX(getMinX());
324   }
325 
326 
327   /**
328    *  Returns the horizontal index of the rightmost column of tiles.
329    *  getMaxTileX() is implemented in terms of getMaxX() and so does not need to
330    *  be implemented by subclasses.
331    *
332    * @return    The MaxTileX value
333    */
334   public int getMaxTileX() {
335     return XToTileX(getMaxX() - 1);
336   }
337 
338 
339   /**
340    *  Returns the number of tiles along the tile grid in the horizontal
341    *  direction. getNumXTiles() is implemented in terms of getMinTileX() and
342    *  getMaxTileX() and so does not need to be implemented by subclasses.
343    *
344    * @return    The NumXTiles value
345    */
346   public int getNumXTiles() {
347     return getMaxTileX() - getMinTileX() + 1;
348   }
349 
350 
351   /**
352    *  Returns the vertical index of the uppermost row of tiles. getMinTileY() is
353    *  implemented in terms of getMinY() and so does not need to be implemented
354    *  by subclasses.
355    *
356    * @return    The MinTileY value
357    */
358   public int getMinTileY() {
359     return YToTileY(getMinY());
360   }
361 
362 
363   /**
364    *  Returns the vertical index of the bottom row of tiles. getMaxTileY() is
365    *  implemented in terms of getMaxY() and so does not need to be implemented
366    *  by subclasses.
367    *
368    * @return    The MaxTileY value
369    */
370   public int getMaxTileY() {
371     return YToTileY(getMaxY() - 1);
372   }
373 
374 
375   /**
376    *  Returns the number of tiles along the tile grid in the vertical direction.
377    *  getNumYTiles() is implemented in terms of getMinTileY() and getMaxTileY()
378    *  and so does not need to be implemented by subclasses.
379    *
380    * @return    The NumYTiles value
381    */
382   public int getNumYTiles() {
383     return getMaxTileY() - getMinTileY() + 1;
384   }
385 
386 
387   /**
388    *  Returns the SampleModel of the image.
389    *
390    * @return    The SampleModel value
391    */
392   public SampleModel getSampleModel() {
393     return sampleModel;
394   }
395 
396 
397   /**
398    *  Returns the ColorModel of the image.
399    *
400    * @return    The ColorModel value
401    */
402   public ColorModel getColorModel() {
403     return colorModel;
404   }
405 
406 
407   /**
408    *  Gets a property from the property set of this image. If the property name
409    *  is not recognized, <code>java.awt.Image.UndefinedProperty</code> will be
410    *  returned.
411    *
412    * @param  name  the name of the property to get, as a <code>String</code>.
413    * @return       a reference to the property <code>Object</code>, or the value
414    *      <code>java.awt.Image.UndefinedProperty.</code>
415    */
416   public Object getProperty(String name) {
417     name = name.toLowerCase();
418     Object value = properties.get(name);
419     return value != null ? value : java.awt.Image.UndefinedProperty;
420   }
421 
422 
423   /**
424    *  Returns a list of the properties recognized by this image. If no
425    *  properties are available, <code>null</code> will be returned.
426    *
427    * @return    an array of <code>String</code>s representing valid property
428    *      names.
429    */
430   public String[] getPropertyNames() {
431     String[] names = null;
432 
433     if (properties.size() > 0) {
434       names = new String[properties.size()];
435       int index = 0;
436 
437       Enumeration e = properties.keys();
438       while (e.hasMoreElements()) {
439         String name = (String) e.nextElement();
440         names[index++] = name;
441       }
442     }
443 
444     return names;
445   }
446 
447 
448   /**
449    *  Returns an array of <code>String</code>s recognized as names by this
450    *  property source that begin with the supplied prefix. If no property names
451    *  match, <code>null</code> will be returned. The comparison is done in a
452    *  case-independent manner. <p>
453    *
454    *  The default implementation calls <code>getPropertyNames()</code> and
455    *  searches the list of names for matches.
456    *
457    * @param  prefix  Description of Parameter
458    * @return         an array of <code>String</code>s giving the valid property
459    *      names.
460    */
461   public String[] getPropertyNames(String prefix) {
462     String propertyNames[] = getPropertyNames();
463     if (propertyNames == null) {
464       return null;
465     }
466 
467     prefix = prefix.toLowerCase();
468 
469     Vector names = new Vector();
470     for (int i = 0; i < propertyNames.length; i++) {
471       if (propertyNames[i].startsWith(prefix)) {
472         names.addElement(propertyNames[i]);
473       }
474     }
475 
476     if (names.size() == 0) {
477       return null;
478     }
479 
480     // Copy the strings from the Vector over to a String array.
481     String prefixNames[] = new String[names.size()];
482     int count = 0;
483     for (Iterator it = names.iterator(); it.hasNext(); ) {
484       prefixNames[count++] = (String) it.next();
485     }
486 
487     return prefixNames;
488   }
489 
490 
491   /**
492    *  Gets the Sources attribute of the SimpleRenderedImage object
493    *
494    * @return    The Sources value
495    */
496   public Vector getSources() {
497     return null;
498   }
499 
500 
501   /**
502    *  Returns the entire image in a single Raster. For images with multiple
503    *  tiles this will require making a copy. <p>
504    *
505    *  The returned Raster is semantically a copy. This means that updates to the
506    *  source image will not be reflected in the returned Raster. For
507    *  non-writable (immutable) source images, the returned value may be a
508    *  reference to the image's internal data. The returned Raster should be
509    *  considered non-writable; any attempt to alter its pixel data (such as by
510    *  casting it to WritableRaster or obtaining and modifying its DataBuffer)
511    *  may result in undefined behavior. The copyData method should be used if
512    *  the returned Raster is to be modified.
513    *
514    * @return    a Raster containing a copy of this image's data.
515    */
516   public Raster getData() {
517     Rectangle rect = new Rectangle(getMinX(), getMinY(),
518         getWidth(), getHeight());
519     return getData(rect);
520   }
521 
522 
523   /**
524    *  Returns an arbitrary rectangular region of the RenderedImage in a Raster.
525    *  The rectangle of interest will be clipped against the image bounds. <p>
526    *
527    *  The returned Raster is semantically a copy. This means that updates to the
528    *  source image will not be reflected in the returned Raster. For
529    *  non-writable (immutable) source images, the returned value may be a
530    *  reference to the image's internal data. The returned Raster should be
531    *  considered non-writable; any attempt to alter its pixel data (such as by
532    *  casting it to WritableRaster or obtaining and modifying its DataBuffer)
533    *  may result in undefined behavior. The copyData method should be used if
534    *  the returned Raster is to be modified.
535    *
536    * @param  bounds  the region of the RenderedImage to be returned.
537    * @return         The Data value
538    */
539   public Raster getData(Rectangle bounds) {
540     // Get the image bounds.
541     Rectangle imageBounds = getBounds();
542 
543     // Check for parameter validity.
544     if (bounds == null) {
545       bounds = imageBounds;
546     }
547     else if (!bounds.intersects(imageBounds)) {
548       throw new IllegalArgumentException(JaiI18N.getString("SimpleRenderedImage0"));
549     }
550 
551     // Determine tile limits for the prescribed bounds.
552     int startX = XToTileX(bounds.x);
553     int startY = YToTileY(bounds.y);
554     int endX = XToTileX(bounds.x + bounds.width - 1);
555     int endY = YToTileY(bounds.y + bounds.height - 1);
556 
557     // If the bounds are contained in a single tile, return a child
558     // of that tile's Raster.
559     if ((startX == endX) && (startY == endY)) {
560       Raster tile = getTile(startX, startY);
561       return tile.createChild(bounds.x, bounds.y,
562           bounds.width, bounds.height,
563           bounds.x, bounds.y, null);
564     }
565     else {
566       // Recalculate the tile limits if the data bounds are not a
567       // subset of the image bounds.
568       if (!imageBounds.contains(bounds)) {
569         Rectangle xsect = bounds.intersection(imageBounds);
570         startX = XToTileX(xsect.x);
571         startY = YToTileY(xsect.y);
572         endX = XToTileX(xsect.x + xsect.width - 1);
573         endY = YToTileY(xsect.y + xsect.height - 1);
574       }
575 
576       // Create a WritableRaster of the desired size
577       SampleModel sm =
578           sampleModel.createCompatibleSampleModel(bounds.width,
579           bounds.height);
580 
581       // Translate it
582       WritableRaster dest =
583           RasterFactory.createWritableRaster(sm, bounds.getLocation());
584 
585       // Loop over the tiles in the intersection.
586       for (int j = startY; j <= endY; j++) {
587         for (int i = startX; i <= endX; i++) {
588           // Retrieve the tile.
589           Raster tile = getTile(i, j);
590 
591           // Create a child of the tile for the intersection of
592           // the tile bounds and the bounds of the requested area.
593           Rectangle tileRect = tile.getBounds();
594           Rectangle intersectRect =
595               bounds.intersection(tile.getBounds());
596           Raster liveRaster = tile.createChild(intersectRect.x,
597               intersectRect.y,
598               intersectRect.width,
599               intersectRect.height,
600               intersectRect.x,
601               intersectRect.y,
602               null);
603 
604           // Copy the data from the child.
605           dest.setRect(liveRaster);
606         }
607       }
608 
609       return dest;
610     }
611   }
612 
613 
614   /**
615    *  Converts a pixel's X coordinate into a horizontal tile index. This is a
616    *  convenience method. No attempt is made to detect out-of-range coordinates.
617    *
618    * @param  x  the X coordinate of a pixel.
619    * @return    the X index of the tile containing the pixel.
620    */
621   public int XToTileX(int x) {
622     return XToTileX(x, getTileGridXOffset(), getTileWidth());
623   }
624 
625 
626   /**
627    *  Converts a pixel's Y coordinate into a vertical tile index. This is a
628    *  convenience method. No attempt is made to detect out-of-range coordinates.
629    *
630    * @param  y  the Y coordinate of a pixel.
631    * @return    the Y index of the tile containing the pixel.
632    */
633   public int YToTileY(int y) {
634     return YToTileY(y, getTileGridYOffset(), getTileHeight());
635   }
636 
637 
638   /**
639    *  Converts a horizontal tile index into the X coordinate of its upper left
640    *  pixel. This is a convenience method. No attempt is made to detect
641    *  out-of-range indices.
642    *
643    * @param  tx  the horizontal index of a tile.
644    * @return     the X coordinate of the tile's upper left pixel.
645    */
646   public int tileXToX(int tx) {
647     return tx * tileWidth + tileGridXOffset;
648   }
649 
650 
651   /**
652    *  Converts a vertical tile index into the Y coordinate of its upper left
653    *  pixel. This is a convenience method. No attempt is made to detect
654    *  out-of-range indices.
655    *
656    * @param  ty  the vertical index of a tile.
657    * @return     the Y coordinate of the tile's upper left pixel.
658    */
659   public int tileYToY(int ty) {
660     return ty * tileHeight + tileGridYOffset;
661   }
662 
663 
664   /**
665    *  Copies an arbitrary rectangular region of the RenderedImage into a
666    *  caller-supplied WritableRaster. The region to be computed is determined by
667    *  clipping the bounds of the supplied WritableRaster against the bounds of
668    *  the image. The supplied WritableRaster must have a SampleModel that is
669    *  compatible with that of the image. <p>
670    *
671    *  If the raster argument is null, the entire image will be copied into a
672    *  newly-created WritableRaster with a SampleModel that is compatible with
673    *  that of the image.
674    *
675    * @param  dest  a WritableRaster to hold the returned portion of the image.
676    * @return       a reference to the supplied WritableRaster, or to a new
677    *      WritableRaster if the supplied one was null.
678    */
679   public WritableRaster copyData(WritableRaster dest) {
680     // Get the image bounds.
681     Rectangle imageBounds = getBounds();
682 
683     Rectangle bounds;
684     if (dest == null) {
685       // Create a WritableRaster for the entire image.
686       bounds = imageBounds;
687       Point p = new Point(minX, minY);
688       SampleModel sm =
689           sampleModel.createCompatibleSampleModel(width, height);
690       dest = RasterFactory.createWritableRaster(sm, p);
691     }
692     else {
693       bounds = dest.getBounds();
694     }
695 
696     // Determine tile limits for the intersection of the prescribed
697     // bounds with the image bounds.
698     Rectangle xsect = imageBounds.contains(bounds) ?
699         bounds : bounds.intersection(imageBounds);
700     int startX = XToTileX(xsect.x);
701     int startY = YToTileY(xsect.y);
702     int endX = XToTileX(xsect.x + xsect.width - 1);
703     int endY = YToTileY(xsect.y + xsect.height - 1);
704 
705     // Loop over the tiles in the intersection.
706     for (int j = startY; j <= endY; j++) {
707       for (int i = startX; i <= endX; i++) {
708         // Retrieve the tile.
709         Raster tile = getTile(i, j);
710 
711         // Create a child of the tile for the intersection of
712         // the tile bounds and the bounds of the requested area.
713         Rectangle tileRect = tile.getBounds();
714         Rectangle intersectRect =
715             bounds.intersection(tile.getBounds());
716         Raster liveRaster = tile.createChild(intersectRect.x,
717             intersectRect.y,
718             intersectRect.width,
719             intersectRect.height,
720             intersectRect.x,
721             intersectRect.y,
722             null);
723 
724         // Copy the data from the child.
725         dest.setRect(liveRaster);
726       }
727     }
728 
729     return dest;
730   }
731 }