You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
22 KiB
604 lines
22 KiB
/* |
|
* Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are met: |
|
* |
|
* -Redistributions of source code must retain the above copyright notice, this |
|
* list of conditions and the following disclaimer. |
|
* |
|
* -Redistribution in binary form must reproduct the above copyright notice, |
|
* this list of conditions and the following disclaimer in the documentation |
|
* and/or other materials provided with the distribution. |
|
* |
|
* Neither the name of Sun Microsystems, Inc. or the names of contributors may |
|
* be used to endorse or promote products derived from this software without |
|
* specific prior written permission. |
|
* |
|
* This software is provided "AS IS," without a warranty of any kind. ALL |
|
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY |
|
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR |
|
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE |
|
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING |
|
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS |
|
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, |
|
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER |
|
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF |
|
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE |
|
* POSSIBILITY OF SUCH DAMAGES. |
|
* |
|
* You acknowledge that Software is not designed,licensed or intended for use in |
|
* the design, construction, operation or maintenance of any nuclear facility. |
|
*/ |
|
package com.fr.third.JAI; |
|
import java.awt.Point; |
|
import java.awt.Rectangle; |
|
import java.awt.image.Raster; |
|
import java.awt.image.WritableRaster; |
|
import java.awt.image.RenderedImage; |
|
import java.awt.image.ColorModel; |
|
import java.awt.image.SampleModel; |
|
import java.util.Enumeration; |
|
import java.util.Hashtable; |
|
import java.util.Iterator; |
|
import java.util.Vector; |
|
|
|
/** |
|
* A simple class implemented the <code>RenderedImage</code> |
|
* interface. Only the <code>getTile()</code> method needs to be |
|
* implemented by subclasses. The instance variables must also be |
|
* filled in properly. |
|
* |
|
* <p> Normally in JAI <code>PlanarImage</code> is used for this |
|
* purpose, but in the interest of making |
|
* <code>com.sun.media.jai.codec</code> and |
|
* <code>com.sun.media.jai.codecimpl</code> be as modular as possible the |
|
* use of <code>PlanarImage</code> has been avoided. |
|
*/ |
|
public abstract class SimpleRenderedImage implements RenderedImage { |
|
|
|
/** The X coordinate of the image's upper-left pixel. */ |
|
protected int minX; |
|
|
|
/** The Y coordinate of the image's upper-left pixel. */ |
|
protected int minY; |
|
|
|
/** The image's width in pixels. */ |
|
protected int width; |
|
|
|
/** The image's height in pixels. */ |
|
protected int height; |
|
|
|
/** The width of a tile. */ |
|
protected int tileWidth; |
|
|
|
/** The height of a tile. */ |
|
protected int tileHeight; |
|
|
|
/** The X coordinate of the upper-left pixel of tile (0, 0). */ |
|
protected int tileGridXOffset = 0; |
|
|
|
/** The Y coordinate of the upper-left pixel of tile (0, 0). */ |
|
protected int tileGridYOffset = 0; |
|
|
|
/** The image's SampleModel. */ |
|
protected SampleModel sampleModel = null; |
|
|
|
/** The image's ColorModel. */ |
|
protected ColorModel colorModel = null; |
|
|
|
/** The image's sources, stored in a Vector. */ |
|
protected Vector sources = new Vector(); |
|
|
|
/** A Hashtable containing the image properties. */ |
|
protected Hashtable properties = new Hashtable(); |
|
|
|
public SimpleRenderedImage() {} |
|
|
|
/** Returns the X coordinate of the leftmost column of the image. */ |
|
public int getMinX() { |
|
return minX; |
|
} |
|
|
|
/** |
|
* Returns the X coordinate of the column immediatetely to the |
|
* right of the rightmost column of the image. getMaxX() is |
|
* implemented in terms of getMinX() and getWidth() and so does |
|
* not need to be implemented by subclasses. |
|
*/ |
|
public final int getMaxX() { |
|
return getMinX() + getWidth(); |
|
} |
|
|
|
/** Returns the X coordinate of the uppermost row of the image. */ |
|
public int getMinY() { |
|
return minY; |
|
} |
|
|
|
/** |
|
* Returns the Y coordinate of the row immediately below the |
|
* bottom row of the image. getMaxY() is implemented in terms of |
|
* getMinY() and getHeight() and so does not need to be |
|
* implemented by subclasses. |
|
*/ |
|
public final int getMaxY() { |
|
return getMinY() + getHeight(); |
|
} |
|
|
|
/** Returns the width of the image. */ |
|
public int getWidth() { |
|
return width; |
|
} |
|
|
|
/** Returns the height of the image. */ |
|
public int getHeight() { |
|
return height; |
|
} |
|
|
|
/** Returns a Rectangle indicating the image bounds. */ |
|
public Rectangle getBounds() { |
|
return new Rectangle(getMinX(), getMinY(), |
|
getWidth(), getHeight()); |
|
} |
|
|
|
/** Returns the width of a tile. */ |
|
public int getTileWidth() { |
|
return tileWidth; |
|
} |
|
|
|
/** Returns the height of a tile. */ |
|
public int getTileHeight() { |
|
return tileHeight; |
|
} |
|
|
|
/** |
|
* Returns the X coordinate of the upper-left pixel of tile (0, 0). |
|
*/ |
|
public int getTileGridXOffset() { |
|
return tileGridXOffset; |
|
} |
|
|
|
/** |
|
* Returns the Y coordinate of the upper-left pixel of tile (0, 0). |
|
*/ |
|
public int getTileGridYOffset() { |
|
return tileGridYOffset; |
|
} |
|
|
|
/** |
|
* Returns the horizontal index of the leftmost column of tiles. |
|
* getMinTileX() is implemented in terms of getMinX() |
|
* and so does not need to be implemented by subclasses. |
|
*/ |
|
public int getMinTileX() { |
|
return XToTileX(getMinX()); |
|
} |
|
|
|
/** |
|
* Returns the horizontal index of the rightmost column of tiles. |
|
* getMaxTileX() is implemented in terms of getMaxX() |
|
* and so does not need to be implemented by subclasses. |
|
*/ |
|
public int getMaxTileX() { |
|
return XToTileX(getMaxX() - 1); |
|
} |
|
|
|
/** |
|
* Returns the number of tiles along the tile grid in the |
|
* horizontal direction. getNumXTiles() is implemented in terms |
|
* of getMinTileX() and getMaxTileX() and so does not need to be |
|
* implemented by subclasses. |
|
*/ |
|
public int getNumXTiles() { |
|
return getMaxTileX() - getMinTileX() + 1; |
|
} |
|
|
|
/** |
|
* Returns the vertical index of the uppermost row of tiles. getMinTileY() |
|
* is implemented in terms of getMinY() and so does not need to be |
|
* implemented by subclasses. |
|
*/ |
|
public int getMinTileY() { |
|
return YToTileY(getMinY()); |
|
} |
|
|
|
/** |
|
* Returns the vertical index of the bottom row of tiles. getMaxTileY() |
|
* is implemented in terms of getMaxY() and so does not need to |
|
* be implemented by subclasses. |
|
*/ |
|
public int getMaxTileY() { |
|
return YToTileY(getMaxY() - 1); |
|
} |
|
|
|
/** |
|
* Returns the number of tiles along the tile grid in the vertical |
|
* direction. getNumYTiles() is implemented in terms |
|
* of getMinTileY() and getMaxTileY() and so does not need to be |
|
* implemented by subclasses. |
|
*/ |
|
public int getNumYTiles() { |
|
return getMaxTileY() - getMinTileY() + 1; |
|
} |
|
|
|
/** Returns the SampleModel of the image. */ |
|
public SampleModel getSampleModel() { |
|
return sampleModel; |
|
} |
|
|
|
/** Returns the ColorModel of the image. */ |
|
public ColorModel getColorModel() { |
|
return colorModel; |
|
} |
|
|
|
/** |
|
* Gets a property from the property set of this image. If the |
|
* property name is not recognized, |
|
* <code>java.awt.Image.UndefinedProperty</code> will be returned. |
|
* |
|
* @param name the name of the property to get, as a |
|
* <code>String</code>. @return a reference to the property |
|
* <code>Object</code>, or the value |
|
* <code>java.awt.Image.UndefinedProperty.</code> |
|
*/ |
|
public Object getProperty(String name) { |
|
name = name.toLowerCase(); |
|
Object value = properties.get(name); |
|
return value != null ? value : java.awt.Image.UndefinedProperty; |
|
} |
|
|
|
/** |
|
* Returns a list of the properties recognized by this image. If |
|
* no properties are available, <code>null</code> will be |
|
* returned. |
|
* |
|
* @return an array of <code>String</code>s representing valid |
|
* property names. |
|
*/ |
|
public String[] getPropertyNames() { |
|
String[] names = null; |
|
|
|
if(properties.size() > 0) { |
|
names = new String[properties.size()]; |
|
int index = 0; |
|
|
|
Enumeration e = properties.keys(); |
|
while (e.hasMoreElements()) { |
|
String name = (String)e.nextElement(); |
|
names[index++] = name; |
|
} |
|
} |
|
|
|
return names; |
|
} |
|
|
|
/** |
|
* Returns an array of <code>String</code>s recognized as names by |
|
* this property source that begin with the supplied prefix. If |
|
* no property names match, <code>null</code> will be returned. |
|
* The comparison is done in a case-independent manner. |
|
* |
|
* <p> The default implementation calls |
|
* <code>getPropertyNames()</code> and searches the list of names |
|
* for matches. |
|
* |
|
* @return an array of <code>String</code>s giving the valid |
|
* property names. |
|
*/ |
|
public String[] getPropertyNames(String prefix) { |
|
String propertyNames[] = getPropertyNames(); |
|
if (propertyNames == null) { |
|
return null; |
|
} |
|
|
|
prefix = prefix.toLowerCase(); |
|
|
|
Vector names = new Vector(); |
|
for (int i = 0; i < propertyNames.length; i++) { |
|
if (propertyNames[i].startsWith(prefix)) { |
|
names.addElement(propertyNames[i]); |
|
} |
|
} |
|
|
|
if (names.size() == 0) { |
|
return null; |
|
} |
|
|
|
// Copy the strings from the Vector over to a String array. |
|
String prefixNames[] = new String[names.size()]; |
|
int count = 0; |
|
for (Iterator it = names.iterator(); it.hasNext(); ) { |
|
prefixNames[count++] = (String)it.next(); |
|
} |
|
|
|
return prefixNames; |
|
} |
|
|
|
// Utility methods. |
|
|
|
/** |
|
* Converts a pixel's X coordinate into a horizontal tile index |
|
* relative to a given tile grid layout specified by its X offset |
|
* and tile width. |
|
*/ |
|
public static int XToTileX(int x, int tileGridXOffset, int tileWidth) { |
|
x -= tileGridXOffset; |
|
if (x < 0) { |
|
x += 1 - tileWidth; // Force round to -infinity |
|
} |
|
return x/tileWidth; |
|
} |
|
|
|
/** |
|
* Converts a pixel's Y coordinate into a vertical tile index |
|
* relative to a given tile grid layout specified by its Y offset |
|
* and tile height. |
|
*/ |
|
public static int YToTileY(int y, int tileGridYOffset, int tileHeight) { |
|
y -= tileGridYOffset; |
|
if (y < 0) { |
|
y += 1 - tileHeight; // Force round to -infinity |
|
} |
|
return y/tileHeight; |
|
} |
|
|
|
/** |
|
* Converts a pixel's X coordinate into a horizontal tile index. |
|
* This is a convenience method. No attempt is made to detect |
|
* out-of-range coordinates. |
|
* |
|
* @param x the X coordinate of a pixel. |
|
* @return the X index of the tile containing the pixel. |
|
*/ |
|
public int XToTileX(int x) { |
|
return XToTileX(x, getTileGridXOffset(), getTileWidth()); |
|
} |
|
|
|
/** |
|
* Converts a pixel's Y coordinate into a vertical tile index. |
|
* This is a convenience method. No attempt is made to detect |
|
* out-of-range coordinates. |
|
* |
|
* @param y the Y coordinate of a pixel. |
|
* @return the Y index of the tile containing the pixel. |
|
*/ |
|
public int YToTileY(int y) { |
|
return YToTileY(y, getTileGridYOffset(), getTileHeight()); |
|
} |
|
|
|
/** |
|
* Converts a horizontal tile index into the X coordinate of its |
|
* upper left pixel relative to a given tile grid layout specified |
|
* by its X offset and tile width. |
|
*/ |
|
public static int tileXToX(int tx, int tileGridXOffset, int tileWidth) { |
|
return tx*tileWidth + tileGridXOffset; |
|
} |
|
|
|
/** |
|
* Converts a vertical tile index into the Y coordinate of |
|
* its upper left pixel relative to a given tile grid layout |
|
* specified by its Y offset and tile height. |
|
*/ |
|
public static int tileYToY(int ty, int tileGridYOffset, int tileHeight) { |
|
return ty*tileHeight + tileGridYOffset; |
|
} |
|
|
|
/** |
|
* Converts a horizontal tile index into the X coordinate of its |
|
* upper left pixel. This is a convenience method. No attempt is made |
|
* to detect out-of-range indices. |
|
* |
|
* @param tx the horizontal index of a tile. |
|
* @return the X coordinate of the tile's upper left pixel. |
|
*/ |
|
public int tileXToX(int tx) { |
|
return tx*tileWidth + tileGridXOffset; |
|
} |
|
|
|
/** |
|
* Converts a vertical tile index into the Y coordinate of its |
|
* upper left pixel. This is a convenience method. No attempt is made |
|
* to detect out-of-range indices. |
|
* |
|
* @param ty the vertical index of a tile. |
|
* @return the Y coordinate of the tile's upper left pixel. |
|
*/ |
|
public int tileYToY(int ty) { |
|
return ty*tileHeight + tileGridYOffset; |
|
} |
|
|
|
public Vector getSources() { |
|
return null; |
|
} |
|
|
|
/** |
|
* Returns the entire image in a single Raster. For images with |
|
* multiple tiles this will require making a copy. |
|
* |
|
* <p> The returned Raster is semantically a copy. This means |
|
* that updates to the source image will not be reflected in the |
|
* returned Raster. For non-writable (immutable) source images, |
|
* the returned value may be a reference to the image's internal |
|
* data. The returned Raster should be considered non-writable; |
|
* any attempt to alter its pixel data (such as by casting it to |
|
* WritableRaster or obtaining and modifying its DataBuffer) may |
|
* result in undefined behavior. The copyData method should be |
|
* used if the returned Raster is to be modified. |
|
* |
|
* @return a Raster containing a copy of this image's data. |
|
*/ |
|
public Raster getData() { |
|
Rectangle rect = new Rectangle(getMinX(), getMinY(), |
|
getWidth(), getHeight()); |
|
return getData(rect); |
|
} |
|
|
|
/** |
|
* Returns an arbitrary rectangular region of the RenderedImage |
|
* in a Raster. The rectangle of interest will be clipped against |
|
* the image bounds. |
|
* |
|
* <p> The returned Raster is semantically a copy. This means |
|
* that updates to the source image will not be reflected in the |
|
* returned Raster. For non-writable (immutable) source images, |
|
* the returned value may be a reference to the image's internal |
|
* data. The returned Raster should be considered non-writable; |
|
* any attempt to alter its pixel data (such as by casting it to |
|
* WritableRaster or obtaining and modifying its DataBuffer) may |
|
* result in undefined behavior. The copyData method should be |
|
* used if the returned Raster is to be modified. |
|
* |
|
* @param bounds the region of the RenderedImage to be returned. |
|
*/ |
|
public Raster getData(Rectangle bounds) { |
|
// Get the image bounds. |
|
Rectangle imageBounds = getBounds(); |
|
|
|
// Check for parameter validity. |
|
if(bounds == null) { |
|
bounds = imageBounds; |
|
} else if(!bounds.intersects(imageBounds)) { |
|
throw new IllegalArgumentException(JaiI18N.getString("SimpleRenderedImage0")); |
|
} |
|
|
|
// Determine tile limits for the prescribed bounds. |
|
int startX = XToTileX(bounds.x); |
|
int startY = YToTileY(bounds.y); |
|
int endX = XToTileX(bounds.x + bounds.width - 1); |
|
int endY = YToTileY(bounds.y + bounds.height - 1); |
|
|
|
// If the bounds are contained in a single tile, return a child |
|
// of that tile's Raster. |
|
if ((startX == endX) && (startY == endY)) { |
|
Raster tile = getTile(startX, startY); |
|
return tile.createChild(bounds.x, bounds.y, |
|
bounds.width, bounds.height, |
|
bounds.x, bounds.y, null); |
|
} else { |
|
// Recalculate the tile limits if the data bounds are not a |
|
// subset of the image bounds. |
|
if(!imageBounds.contains(bounds)) { |
|
Rectangle xsect = bounds.intersection(imageBounds); |
|
startX = XToTileX(xsect.x); |
|
startY = YToTileY(xsect.y); |
|
endX = XToTileX(xsect.x + xsect.width - 1); |
|
endY = YToTileY(xsect.y + xsect.height - 1); |
|
} |
|
|
|
// Create a WritableRaster of the desired size |
|
SampleModel sm = |
|
sampleModel.createCompatibleSampleModel(bounds.width, |
|
bounds.height); |
|
|
|
// Translate it |
|
WritableRaster dest = |
|
RasterFactory.createWritableRaster(sm, bounds.getLocation()); |
|
|
|
// Loop over the tiles in the intersection. |
|
for (int j = startY; j <= endY; j++) { |
|
for (int i = startX; i <= endX; i++) { |
|
// Retrieve the tile. |
|
Raster tile = getTile(i, j); |
|
|
|
// Create a child of the tile for the intersection of |
|
// the tile bounds and the bounds of the requested area. |
|
Rectangle tileRect = tile.getBounds(); |
|
Rectangle intersectRect = |
|
bounds.intersection(tile.getBounds()); |
|
Raster liveRaster = tile.createChild(intersectRect.x, |
|
intersectRect.y, |
|
intersectRect.width, |
|
intersectRect.height, |
|
intersectRect.x, |
|
intersectRect.y, |
|
null); |
|
|
|
// Copy the data from the child. Note that |
|
// WritableRaster.setDataElements takes into account of |
|
// inRaster's minX and minY and add these to x and y. Since |
|
// liveRaster has the origin at the correct location, the |
|
// following call should not again give these coordinates in |
|
// places of x and y. |
|
dest.setDataElements(0, 0, liveRaster); |
|
} |
|
} |
|
|
|
return dest; |
|
} |
|
} |
|
|
|
/** |
|
* Copies an arbitrary rectangular region of the RenderedImage |
|
* into a caller-supplied WritableRaster. The region to be |
|
* computed is determined by clipping the bounds of the supplied |
|
* WritableRaster against the bounds of the image. The supplied |
|
* WritableRaster must have a SampleModel that is compatible with |
|
* that of the image. |
|
* |
|
* <p> If the raster argument is null, the entire image will |
|
* be copied into a newly-created WritableRaster with a SampleModel |
|
* that is compatible with that of the image. |
|
* |
|
* @param dest a WritableRaster to hold the returned portion of |
|
* the image. |
|
* @return a reference to the supplied WritableRaster, or to a |
|
* new WritableRaster if the supplied one was null. |
|
*/ |
|
public WritableRaster copyData(WritableRaster dest) { |
|
// Get the image bounds. |
|
Rectangle imageBounds = getBounds(); |
|
|
|
Rectangle bounds; |
|
if (dest == null) { |
|
// Create a WritableRaster for the entire image. |
|
bounds = imageBounds; |
|
Point p = new Point(minX, minY); |
|
SampleModel sm = |
|
sampleModel.createCompatibleSampleModel(width, height); |
|
dest = RasterFactory.createWritableRaster(sm, p); |
|
} else { |
|
bounds = dest.getBounds(); |
|
} |
|
|
|
// Determine tile limits for the intersection of the prescribed |
|
// bounds with the image bounds. |
|
Rectangle xsect = imageBounds.contains(bounds) ? |
|
bounds : bounds.intersection(imageBounds); |
|
int startX = XToTileX(xsect.x); |
|
int startY = YToTileY(xsect.y); |
|
int endX = XToTileX(xsect.x + xsect.width - 1); |
|
int endY = YToTileY(xsect.y + xsect.height - 1); |
|
|
|
// Loop over the tiles in the intersection. |
|
for (int j = startY; j <= endY; j++) { |
|
for (int i = startX; i <= endX; i++) { |
|
// Retrieve the tile. |
|
Raster tile = getTile(i, j); |
|
|
|
// Create a child of the tile for the intersection of |
|
// the tile bounds and the bounds of the requested area. |
|
Rectangle tileRect = tile.getBounds(); |
|
Rectangle intersectRect = |
|
bounds.intersection(tile.getBounds()); |
|
Raster liveRaster = tile.createChild(intersectRect.x, |
|
intersectRect.y, |
|
intersectRect.width, |
|
intersectRect.height, |
|
intersectRect.x, |
|
intersectRect.y, |
|
null); |
|
|
|
// Copy the data from the child. Note that |
|
// WritableRaster.setDataElements takes into account of |
|
// inRaster's minX and minY and add these to x and y. Since |
|
// liveRaster has the origin at the correct location, the |
|
// following call should not again give these coordinates in |
|
// places of x and y. |
|
dest.setDataElements(0, 0, liveRaster); |
|
} |
|
} |
|
|
|
return dest; |
|
} |
|
}
|
|
|