home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Java 1.2 How-To
/
JavaHowTo.iso
/
3rdParty
/
jbuilder
/
unsupported
/
JDK1.2beta3
/
SOURCE
/
SRC.ZIP
/
java
/
awt
/
image
/
BufferedImage.java
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Java Source
|
1998-03-20
|
42.9 KB
|
1,198 lines
/*
* @(#)BufferedImage.java 1.56 98/03/18
*
* Copyright 1997, 1998 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
package java.awt.image;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Point2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Vector;
import sun.awt.image.BytePackedRaster;
import sun.awt.image.ShortComponentRaster;
import sun.awt.image.ByteComponentRaster;
import sun.awt.image.IntegerComponentRaster;
/**
*
* This subclass describes an Image with an accessible buffer of image data.
* A BufferedImage is comprised of a ColorModel and a Raster of image data.
* The number and types of bands in the SampleModel of the Raster must match
* the number and types required by the ColorModel to represent its color
* and alpha components. All BufferedImages have an upper left corner
* coordinate of 0,0. Any Raster used to construct a BufferedImage must
* therefore have minX=0 and minY=0.
* @see ColorModel
* @see Raster
* @see WritableRaster
* @version 10 Feb 1997
*/
public class BufferedImage extends java.awt.Image
implements WritableRenderedImage {
int imageType = TYPE_CUSTOM;
ColorModel colorModel;
WritableRaster raster;
TileChangeMulticaster tcm = new TileChangeMulticaster();
boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in
// color channels
/**
* Image Type Constants
*/
/**
* Image type is not recognized so it must be a customized
* image. This type is only used as a return value for the getType()
* method.
*/
public static final int TYPE_CUSTOM = 0;
/**
* Represents an image with 8-bit RGB color components packed into
* integer pixels. The image has a DirectColorModel (without alpha).
*/
public static final int TYPE_INT_RGB = 1;
/**
* Represents an image with 8-bit RGBA color components packed into
* integer pixels. The image has a DirectColorModel (with alpha).
* The color data in this image
* is considered not to be premultiplied with alpha. When
* this type is used as the imageType argument to a BufferedImage
* constructor, the image created will be
* consistent with images created in the JDK1.1 and earlier releases.
*/
public static final int TYPE_INT_ARGB = 2;
/**
* Represents an image with 8-bit RGBA color components packed into
* integer pixels. The image has a DirectColorModel (with alpha).
* The color data in this image is considered to be premultiplied
* with alpha.
*/
public static final int TYPE_INT_ARGB_PRE = 3;
/**
* Represents an image with 8-bit RGB color components (corresponds to
* a Windows- or Solaris- style BGR color model) with the colors
* Blue, Green, and Red packed into integer pixels. There is no alpha.
* The image has a ComponentColorModel.
*/
public static final int TYPE_INT_BGR = 4;
/**
* Represents an image with 8-bit RGB color components (corresponds to
* a Windows-style BGR color model) with the colors Blue, Green,
* and Red stored in 3 bytes. There is no alpha. The image has a
* ComponentColorModel.
*/
public static final int TYPE_3BYTE_BGR = 5;
/**
* Represents an image with 8-bit RGBA color components with the colors
* Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
* image has a
* ComponentColorModel (with alpha). The color data in this image
* will be considered not to be premultiplied with alpha. The byte
* data is interleaved in a single byte array in the order A, B, G, R
* from lower to higher byte addresses within each pixel.
*/
public static final int TYPE_4BYTE_ABGR = 6;
/**
* Represents an image with 8-bit RGBA color components with the colors
* Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
* image has
* a ComponentColorModel (with alpha). The color
* data in this image will be considered to be premultiplied with alpha.
* The byte data is interleaved in a single byte array in the order
* A, B, G, R from lower to higher byte addresses within each pixel.
*/
public static final int TYPE_4BYTE_ABGR_PRE = 7;
/**
* Represents an image with 5-6-5 RGB color components (5-bits red,
* 6-bits green, 5-bits blue) with no alpha. This image has
* a DirectColorModel.
*/
public static final int TYPE_SHORT_565_RGB = 8;
/**
* Represents an image with 5-5-5 RGB color components (5-bits red,
* 5-bits green, 5-bits blue) with no alpha. This image has
* a DirectColorModel.
*/
public static final int TYPE_SHORT_555_RGB = 9;
/**
* Represents a grayscale image (non-indexed). This image has a
* ComponentColorModel with a CS_GRAY ColorSpace.
*/
public static final int TYPE_BYTE_GRAY = 10;
/**
* Represents an opaque binary image. The
* image has an IndexColorModel
* (without alpha). When this type is used as the imageType argument
* to the BufferedImage constructor which takes an imageType argument
* but no ColorModel argument, an IndexColorModel will be created with
* two colors in the default sRGB ColorSpace: {0, 0, 0} and
* {255, 255, 255}.
*/
public static final int TYPE_BINARY = 11;
/**
* Represents an indexed byte image
* When this type is used as the imageType argument
* to the BufferedImage constructor which takes an imageType argument
* but no ColorModel argument, an IndexColorModel will be created with
* an 8-bit grayscale ramp in the default sRGB ColorSpace.
*/
public static final int TYPE_BYTE_INDEXED = 12;
public static final int DCM_RED_MASK = 0x00ff0000;
public static final int DCM_GREEN_MASK = 0x0000ff00;
public static final int DCM_BLUE_MASK = 0x000000ff;
public static final int DCM_ALPHA_MASK = 0xff000000;
public static final int DCM_565_RED_MASK = 0xf800;
public static final int DCM_565_GRN_MASK = 0x07E0;
public static final int DCM_565_BLU_MASK = 0x001F;
public static final int DCM_555_RED_MASK = 0x7C00;
public static final int DCM_555_GRN_MASK = 0x03E0;
public static final int DCM_555_BLU_MASK = 0x001F;
public static final int DCM_BGR_RED_MASK = 0x0000ff;
public static final int DCM_BGR_GRN_MASK = 0x00ff00;
public static final int DCM_BGR_BLU_MASK = 0xff0000;
static private native void initIDs();
static {
ColorModel.loadLibraries();
initIDs();
}
/**
* Constructs a BufferedImage of one of the predefined image types.
* The ColorSpace for the image will be the default sRGB space.
* @param width Width of the created image.
* @param height Height of the created image.
* @param imageType Type of the created image.
* @see ColorSpace
* @see TYPE_INT_RGB
* @see TYPE_INT_ARGB
* @see TYPE_INT_ARGB_PRE
* @see TYPE_INT_BGR
* @see TYPE_3BYTE_BGR
* @see TYPE_4BYTE_ABGR
* @see TYPE_4BYTE_ABGR_PRE
* @see TYPE_BYTE_GRAY
* @see TYPE_BINARY
* @see TYPE_BYTE_INDEXED
* @see TYPE_SHORT_565_RGB
* @see TYPE_SHORT_555_RGB
*/
public BufferedImage (int width,
int height,
int imageType) {
switch (imageType) {
case TYPE_INT_RGB:
{
colorModel = new DirectColorModel(24,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0x0 // Alpha
);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
case TYPE_INT_ARGB:
{
colorModel = new DirectColorModel(32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0xff000000 // Alpha
);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
case TYPE_INT_ARGB_PRE:
{
colorModel = new
DirectColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
32,
0x00ff0000,// Red
0x0000ff00,// Green
0x000000ff,// Blue
0xff000000,// Alpha
true // Alpha Premultiplied
);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
case TYPE_INT_BGR:
{
colorModel = new DirectColorModel(24,
0x000000ff, // Red
0x0000ff00, // Green
0x00ff0000 // Blue
);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
case TYPE_3BYTE_BGR:
{
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8};
int[] bOffs = {2, 1, 0};
colorModel = new ComponentColorModel(cs, nBits, false, false,
Transparency.OPAQUE);
raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
width, height, width*3,
3, bOffs, null);
}
break;
case TYPE_4BYTE_ABGR:
{
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8, 8};
int[] bOffs = {3, 2, 1, 0};
colorModel = new ComponentColorModel(cs, nBits, true, false,
Transparency.TRANSLUCENT);
raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
width, height, width*4,
4, bOffs, null);
}
break;
case TYPE_4BYTE_ABGR_PRE:
{
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8, 8};
int[] bOffs = {3, 2, 1, 0};
colorModel = new ComponentColorModel(cs, nBits, true, true,
Transparency.TRANSLUCENT);
raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
width, height, width*4,
4, bOffs, null);
}
break;
case TYPE_BYTE_GRAY:
{
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
int[] nBits = {8};
colorModel = new ComponentColorModel(cs, nBits, false, true,
Transparency.OPAQUE);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
case TYPE_BINARY:
{
byte[] arr = {(byte)0, (byte)0xff};
colorModel = new IndexColorModel(1, 2, arr, arr, arr);
raster = Raster.createPackedRaster(DataBuffer.BYTE_DATA,
width, height, 1, 1, null);
}
break;
case TYPE_BYTE_INDEXED:
{
// Create a grayscale ramp
int[] cmap = new int[256];
for (int i=0; i < 256; i++) {
cmap[i] = (i<<16)|(i<<8)|i;
}
colorModel = new IndexColorModel (8, 256, cmap, 0, false,
-1, true);
raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
width, height, 1, null);
}
break;
case TYPE_SHORT_565_RGB:
{
colorModel = new DirectColorModel(16,
DCM_565_RED_MASK,
DCM_565_GRN_MASK,
DCM_565_BLU_MASK
);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
case TYPE_SHORT_555_RGB:
{
colorModel = new DirectColorModel(15,
DCM_555_RED_MASK,
DCM_555_GRN_MASK,
DCM_555_BLU_MASK
);
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
default:
throw new IllegalArgumentException ("Unknown image type " +
imageType);
}
this.imageType = imageType;
}
/**
* Constructs a BufferedImage of one of the predefined image types:
* TYPE_BINARY or TYPE_BYTE_INDEXED
* @param width Width of the created image.
* @param height Height of the created image.
* @param imageType Type of the created image.
* @param cm IndexColorModel of the created image.
* @throws IllegalArgumentException if the imageType is not
* TYPE_BINARY or TYPE_BYTE_INDEXED
* @see TYPE_BINARY
* @see TYPE_BYTE_INDEXED
*/
public BufferedImage (int width,
int height,
int imageType,
IndexColorModel cm) {
if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
throw new IllegalArgumentException("This image types do not have "+
"premultiplied alpha.");
}
switch(imageType) {
case TYPE_BINARY:
raster = Raster.createPackedRaster(DataBuffer.BYTE_DATA,
width, height, 1, 1, null);
break;
case TYPE_BYTE_INDEXED:
raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
width, height, 1, null);
break;
default:
throw new IllegalArgumentException("Unknown image type " +
imageType);
}
if (!cm.isCompatibleRaster(raster)) {
throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
}
colorModel = cm;
this.imageType = imageType;
}
/**
* Constructs a new BufferedImage with a given ColorModel
* and Raster. If the number and types of bands in the SampleModel
* of the Raster do not match the number and types required by the
* ColorModel to represent its color and alpha components,
* an exception will be thrown. This method may multiply or divide
* the color Raster data by alpha to match the alphaPremultiplied state
* in the ColorModel.
* @param ColorModel ColorModel for the new image
* @param raster Raster for the image data
* @param isRasterPremultiplied If true, the data in the raster has been
* premultiplied with alpha.
* @see ColorModel
* @see Raster
* @see WritableRaster
*/
/*
*
* FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
* SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
*
*/
public BufferedImage (ColorModel cm,
WritableRaster raster,
boolean isRasterPremultiplied) {
if (!cm.isCompatibleRaster(raster)) {
throw new
IllegalArgumentException("Raster "+raster+
" is incompatible with ColorModel "+
cm);
}
if ((raster.minX != 0) || (raster.minY != 0)) {
throw new
IllegalArgumentException("Raster "+raster+
" has minX or minY not equal to zero: "
+ raster.minX + " " + raster.minY);
}
colorModel = cm;
this.raster = raster;
int numBands = raster.getNumBands();
boolean isAlphaPre = cm.isAlphaPremultiplied();
ColorSpace cs;
// Force the raster data alpha state to match the premultiplied
// state in the color model
coerceData(isRasterPremultiplied);
cs = cm.getColorSpace();
int csType = cs.getType();
if (csType != ColorSpace.TYPE_RGB) {
if (csType == ColorSpace.TYPE_GRAY
&& raster instanceof ByteComponentRaster
&& cm instanceof ComponentColorModel) {
imageType = TYPE_BYTE_GRAY;
}
else {
imageType = TYPE_CUSTOM;
}
return;
}
if ((raster instanceof IntegerComponentRaster) &&
(numBands == 3 || numBands == 4)) {
IntegerComponentRaster iraster =
(IntegerComponentRaster) raster;
// Check if the raster params and the color model
// are correct
int pixSize = cm.getPixelSize();
if (iraster.getPixelStride() == 1 &&
cm instanceof DirectColorModel &&
(pixSize == 32 || pixSize == 24))
{
// Now check on the DirectColorModel params
DirectColorModel dcm = (DirectColorModel) cm;
int rmask = dcm.getRedMask();
int gmask = dcm.getGreenMask();
int bmask = dcm.getBlueMask();
if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK &&
bmask == DCM_BLUE_MASK)
{
if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
imageType = (isAlphaPre
? TYPE_INT_ARGB_PRE
: TYPE_INT_ARGB);
}
else {
// No Alpha
if (!dcm.hasAlpha()) {
imageType = TYPE_INT_RGB;
}
}
} // if (dcm.getRedMask() == DCM_RED_MASK &&
else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK
&& bmask == DCM_BGR_BLU_MASK) {
if (!dcm.hasAlpha()) {
imageType = TYPE_INT_BGR;
}
} // if (rmask == DCM_BGR_RED_MASK &&
} // if (iraster.getPixelStride() == 1
} // ((raster instanceof IntegerComponentRaster) &&
else if ((cm instanceof IndexColorModel) && (numBands == 1) &&
(!cm.hasAlpha() || !isAlphaPre))
{
IndexColorModel icm = (IndexColorModel) cm;
int pixSize = icm.getPixelSize();
if (raster instanceof BytePackedRaster) {
BytePackedRaster braster = (BytePackedRaster) raster;
if (braster.getNumberOfBits() == 1 &&
braster.getPixelBitStride() == 1 &&
pixSize == 1 &&
icm.getMapSize() == 2)
{
imageType = TYPE_BINARY;
}
} // if (raster instanceof BytePackedRaster)
else if (raster instanceof ByteComponentRaster) {
ByteComponentRaster braster = (ByteComponentRaster) raster;
if (braster.getPixelStride() == 1 && pixSize <= 8) {
imageType = TYPE_BYTE_INDEXED;
}
}
} // else if (cm instanceof IndexColorModel) && (numBands == 1))
else if ((raster instanceof ShortComponentRaster)
&& (cm instanceof DirectColorModel)
&& (numBands == 3)
&& !cm.hasAlpha())
{
DirectColorModel dcm = (DirectColorModel) cm;
if (dcm.getRedMask() == DCM_565_RED_MASK) {
if (dcm.getGreenMask() == DCM_565_GRN_MASK &&
dcm.getBlueMask() == DCM_565_BLU_MASK) {
imageType = TYPE_SHORT_565_RGB;
}
}
else if (dcm.getRedMask() == DCM_555_RED_MASK) {
if (dcm.getGreenMask() == DCM_555_GRN_MASK &&
dcm.getBlueMask() == DCM_555_BLU_MASK) {
imageType = TYPE_SHORT_555_RGB;
}
}
} // else if ((cm instanceof IndexColorModel) && (numBands == 1))
else if ((raster instanceof ByteComponentRaster)
&& (cm instanceof ComponentColorModel)
&& (numBands == 3 || numBands == 4))
{
ComponentColorModel ccm = (ComponentColorModel) cm;
ByteComponentRaster braster = (ByteComponentRaster) raster;
int[] offs = braster.getDataOffsets();
if (ccm.getNumComponents() != numBands) {
throw new RasterFormatException("Number of components in "+
"ColorModel ("+
ccm.getNumComponents()+
") does not match # in "+
" Raster ("+numBands+")");
}
if (braster.getPixelStride() == 1 &&
offs[0] == numBands-1 &&
offs[1] == numBands-2 &&
offs[2] == numBands-3)
{
if (numBands == 3) {
imageType = TYPE_3BYTE_BGR;
}
else if (offs[3] == 0) {
imageType = (isAlphaPre
? TYPE_4BYTE_ABGR_PRE
: TYPE_4BYTE_ABGR);
}
}
} // else if ((raster instanceof ByteComponentRaster) &&
}
/**
* Returns the image type. If it is not one of the known types,
* TYPE_CUSTOM is returned.
* @see TYPE_INT_RGB
* @see TYPE_INT_ARGB
* @see TYPE_INT_ARGB_PRE
* @see TYPE_3BYTE_BGR
* @see TYPE_4BYTE_ABGR
* @see TYPE_4BYTE_ABGR_PRE
* @see TYPE_SHORT_565_RGB
* @see TYPE_SHORT_555_RGB
* @see TYPE_BYTE_GRAY
* @see TYPE_BINARY
* @see TYPE_BYTE_INDEXED
* @see TYPE_CUSTOM
*/
public int getType() {
return imageType;
}
/**
* Returns the ColorModel.
*/
public ColorModel getColorModel() {
return colorModel;
}
/**
* Returns the Raster.
*/
public WritableRaster getRaster() {
return raster;
}
/**
* Returns a Raster representing the alpha channel for BufferedImages
* with ColorModels that support a separate spatial alpha channel
* (such as ComponentColorModel and DirectColorModel).
* Returns null if there is no alpha
* channel associated with the ColorModel in this image.
* This method assumes that for all ColorModels other than IndexColorModel,
* if the ColorModel supports alpha, there is a separate alpha channel
* which is stored as the last band of image data.
* If the image uses an IndexColorModel which
* has alpha in the lookup table, this method will return null since
* there is no spatially discrete alpha channel.
* This method will create a new Raster (but will share the data
* array).
*/
public WritableRaster getAlphaRaster() {
// No Alpha
if (colorModel.hasAlpha() == false) {
return null;
}
// IndexColorModel -- so no spatially discrete alpha
if (colorModel instanceof IndexColorModel) {
return null;
}
// For now, assume the alpha channel is the last band in the raster.
int x = raster.getMinX();
int y = raster.getMinY();
int[] band = new int[1];
band[0] = raster.getNumBands() - 1;
return raster.createWritableSubRaster(x, y, raster.getWidth(),
raster.getHeight(), x, y,
band);
}
/**
* Returns an integer pixel in the default RGB color model
* (TYPE_INT_ARGB) and default sRGB colorspace. Color
* conversion will take place if this default model does not match
* the image ColorModel. There are only 8-bits of precision
* for each color component in the returned data when using this method.
*/
public int getRGB(int x, int y) {
return colorModel.getRGB(raster.getPixelData(x, y, null));
}
/**
* Returns an array of integer pixels in the default RGB color model
* (TYPE_INT_ARGB) and default sRGB color space,
* from a portion of the image data. Color conversion will take place
* if the default model does not match the image ColorModel. There
* are only 8-bits of precision for each color component in
* the returned data when
* using this method. Given a coordinate (x,y) in the image, the
* ARGB pixel can be accessed using the following:
* <pre>
* pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
* </pre>
* @param startX Starting x Coordinate
* @param startY Starting y Coordinate
* @param w Width of region
* @param h Height of region
* @param rgbArray If non-null, the rgb pixels will be written here
* @param offset Offset into the rgbArray
* @param scansize Scanline stride for the rgbArray
* @return Array of RGB pixels.
*/
public int[] getRGB(int startX, int startY, int w, int h,
int[] rgbArray, int offset, int scansize) {
int yoff = offset;
int off;
Object data;
int nbands = raster.getNumBands();
int dataType = raster.getDataBuffer().getDataType();
switch (dataType) {
case DataBuffer.BYTE_DATA:
data = new byte[nbands];
break;
case DataBuffer.SHORT_DATA:
data = new short[nbands];
break;
case DataBuffer.INT_DATA:
data = new int[nbands];
break;
case DataBuffer.LONG_DATA:
data = new long[nbands];
break;
case DataBuffer.FLOAT_DATA:
data = new float[nbands];
break;
case DataBuffer.DOUBLE_DATA:
data = new double[nbands];
break;
default:
throw new IllegalArgumentException("Unknown data buffer type: "+
dataType);
}
if (rgbArray == null) {
rgbArray = new int[offset+h*scansize];
}
for (int y = startY; y < startY+h; y++, yoff+=scansize) {
off = yoff;
for (int x = startX; x < startX+w; x++) {
rgbArray[off++] = colorModel.getRGB(raster.getPixelData(x,
y,
data));
}
}
return rgbArray;
}
/**
* Set a pixel in a BufferedImage. The pixel is assumed
* to be in the default RGB color model (TYPE_INT_ARGB) and
* default sRGB color space. For images with an
* IndexColorModel, the index with the nearest color will be
* chosen.
*/
public synchronized void setRGB(int x, int y, int rgb) {
raster.setPixelData(x, y, colorModel.getPixelData(rgb, null));
}
/**
* Sets an array of integer pixels in the default RGB color model
* (TYPE_INT_ARGB) and default sRGB color space,
* into a portion of the image data. Color conversion will take place
* if the default model does not match the image ColorModel. There
* are only 8-bits of precision for each color component in
* the returned data when
* using this method. Given a coordinate (x,y) in the image, the
* ARGB pixel can be accessed using the following:
* <pre>
* pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
* </pre>
* WARNING: No dithering will take place.
*
* @param startX Starting x Coordinate
* @param startY Starting y Coordinate
* @param w Width of region
* @param h Height of region
* @param rgbArray The rgb pixels
* @param offset Offset into the rgbArray
* @param scansize Scanline stride for the rgbArray
*/
public void setRGB(int startX, int startY, int w, int h,
int[] rgbArray, int offset, int scansize) {
int yoff = offset;
int off;
Object pixel = null;
for (int y = startY; y < startY+h; y++, yoff+=scansize) {
off = yoff;
for (int x = startX; x < startX+w; x++) {
pixel = colorModel.getPixelData(rgbArray[off], pixel);
raster.setPixelData(x, y, pixel);
}
}
}
/**
* Returns the width of the BufferedImage.
*/
public int getWidth() {
return raster.getWidth();
}
/**
* Returns the height of the BufferedImage.
*/
public int getHeight() {
return raster.getHeight();
}
/**
* Returns the actual width of the image. If the width is not known
* yet, then the ImageObserver will be notified later and -1 will
* be returned.
* @see java.awt.Image#getHeight
* @see java.awt.ImageObserver
*/
public int getWidth(ImageObserver observer) {
return raster.getWidth();
}
/**
* Returns the actual height of the image. If the height is not known
* yet, then the ImageObserver will be notified later and -1 will
* be returned.
* @see java.awt.Image#getWidth
* @see ImageObserver
*/
public int getHeight(ImageObserver observer) {
return raster.getHeight();
}
/**
* Returns the object that produces the pixels for the image. This
* returns null.
* @see ImageProducer
*/
public ImageProducer getSource() {
return null;
}
/**
* Returns a property of the image by name. Individual property names
* are defined by the various image formats. If a property is not
* defined for a particular image, this method will return the
* UndefinedProperty object. If the properties for this image are
* not yet known, then this method will return null and the ImageObserver
* object will be notified later. The property name "comment" should
* be used to store an optional comment which can be presented to
* the user as a description of the image, its source, or its author.
* @see ImageObserver
* @see java.awt.Image#UndefinedProperty
*/
public Object getProperty(String name, ImageObserver observer) {
return null;
}
/**
* Returns a property of the image by name.
*/
public Object getProperty(String name) {
return null;
}
/**
* Flushes all resources being used to cache optimization information.
* The underlying pixel data is unaffected.
*/
public void flush() {
}
/**
* This method will actually return a Graphics2D but is here
* for backwards compatibility.
* @deprecated
*/
public java.awt.Graphics getGraphics() {
return createGraphics();
}
/**
* Creates a Graphics2D, which can be used to draw into this
* BufferedImage.
*/
public Graphics2D createGraphics() {
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
return env.createGraphics(this);
}
/**
* Returns a subimage given a rectangular region.
* The returned BufferedImage will share the same
* data array as the original image.
*/
public BufferedImage getSubimage (int x, int y, int w, int h) {
return new BufferedImage (colorModel,
raster.createWritableSubRaster(x, y, w, h,
0, 0, null),
colorModel.isAlphaPremultiplied());
}
/**
* Returns whether or not the alpha has been premultiplied. It
* will return true if there is no alpha since the default alpha
* is OPAQUE.
*/
public boolean isAlphaPremultiplied() {
return colorModel.isAlphaPremultiplied();
}
/**
* Forces the data to match the state specified in the
* isAlphaPremultiplied variable. It may multiply or divide the
* color Raster data by alpha, or do nothing if the data is
* in the correct state.
*/
public void coerceData (boolean isAlphaPremultiplied) {
if (colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
// Make the color model do the conversion
colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
}
}
public String toString() {
return new String("BufferedImage@"+Integer.toHexString(hashCode())
+": type = "+imageType
+" "+colorModel+" "+raster);
}
/**
* Return a vector of RenderedImages that are the sources of
* Image data for this RenderedImage. Note that this method
* will often return null.
*/
public Vector getSources() {
return null;
}
/**
* Return a list of names recognized by getProperty(String).
*/
public String[] getPropertyNames() {
return null;
}
/**
* Return the minimum x coordinate of the rendered image. For some
* image with infinite extent, it could be int.MIN_VALUE.
*/
public int getMinXCoord() {
return raster.getMinX();
}
/**
* Return the maximum x coordinate of the rendered image. For some
* image with infinite extent, it could be int.MAX_VALUE.
*/
public int getMaxXCoord() {
return raster.getMinX() + raster.getWidth();
}
/**
* Return the minimum y coordinate of the rendered image. For some
* image with infinite extent, it could be int.MIN_VALUE.
*/
public int getMinYCoord() {
return raster.getMinY();
}
/**
* Return the minimum y coordinate of the rendered image. For some
* image with infinite extent, it could be int.MAX_VALUE.
*/
public int getMaxYCoord() {
return raster.getMinY() + raster.getHeight();
}
/** Return the sample model associated with this image */
public SampleModel getSampleModel() {
return raster.getSampleModel();
}
/** Return the number of tiles across the image */
public int tilesAcross() {
return 1;
}
/** Return the number of tiles down the image */
public int tilesDown() {
return 1;
}
/** Return the index of the min tile in the x direction of the image */
public int getMinTileX() {
return 0;
}
/** Return the index of the max tile in the x direction of the image */
public int getMaxTileX() {
return 0;
}
/** Return the index of the min tile in the y direction of the image */
public int getMinTileY() {
return 0;
}
/** Return the index of the max tile in the y direction of the image */
public int getMaxTileY(){
return 0;
}
/** Return the width of tile in pixel */
public int getTileWidth() {
return raster.getSampleModel().getWidth();
}
/** Return the height of the tile in pixel */
public int getTileHeight() {
return raster.getSampleModel().getHeight();
}
/** Return the X offset of tile grid relative to the origin */
public int getTileGridXOffset() {
return raster.getBaseRasterOriginX();
}
/** Return the Y offset of tile grid relative to the origin */
public int getTileGridYOffset() {
return raster.getBaseRasterOriginY();
}
/**
* Return tile# x, y. Note that x and y are indexes into the
* tile array not pixel locations. The Raster that is returned
* is live and will be updated if the image is changed.
* @param x the x index of the requested tile in the tile array
* @param y the y index of the requested tile in the tile array
*/
public Raster getTile(int x, int y) {
if (x == 0 && y == 0) {
return raster;
}
throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
" one tile with index 0,0");
}
/**
* Return the image as one large tile (for tile based
* images this will require fetching the whole image
* and copying the image data over). The Raster returned is
* semantically a copy.
*/
public Raster getData() {
// REMIND : this allocates a whole new tile if raster is a
// subtile. (It only copies in the requested area)
// We should do something smarter.
int width = raster.getWidth();
int height = raster.getHeight();
int startX = raster.getMinX();
int startY = raster.getMinY();
WritableRaster wr =
Raster.createWritableRaster(raster.getSampleModel(),
new Point(raster.getBaseRasterOriginX(),
raster.getBaseRasterOriginY()));
Object tdata = null;
for (int i = startY; i < startY+height; i++) {
tdata = raster.getPixelData(startX,i,width,1,tdata);
wr.setPixelData(startX,i,width,1, tdata);
}
return wr;
}
/**
* Compute and return an arbitrary region of the RenderedImage.
* Note that in general this may involve copying image data.
* The Raster returned is semantically a copy.
* @param rect the region of the RenderedImage to be returned.
*/
public Raster getRect(Rectangle rect) {
SampleModel sm = raster.getSampleModel();
SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
rect.height);
WritableRaster wr = Raster.createWritableRaster(nsm,
rect.getLocation());
int width = rect.width;
int height = rect.height;
int startX = rect.x;
int startY = rect.y;
Object tdata = null;
for (int i = startY; i < startY+height; i++) {
tdata = raster.getPixelData(startX,i,width,1,tdata);
wr.setPixelData(startX,i,width,1, tdata);
}
return wr;
}
/**
* Compute an arbitrary rectangular region of the RenderedImage
* and copy it into a caller-supplied WritableRaster. The region
* to be computed is determined from the bounds of the supplied
* WritableRaster. The supplied WritableRaster must have a ColorModel
* and SampleModel that are compatible with those of this image.
* @param raster a WritableRaster to hold the returned part of the image.
* @return a reference to the supplied WritableRaster.
*/
public WritableRaster getRect(WritableRaster outRaster) {
int width = outRaster.getWidth();
int height = outRaster.getHeight();
int startX = outRaster.getMinX();
int startY = outRaster.getMinY();
Object tdata = null;
for (int i = startY; i < startY+height; i++) {
tdata = raster.getPixelData(startX,i,width,1,tdata);
outRaster.setPixelData(startX,i,width,1, tdata);
}
return outRaster;
}
/**
* Set a rect of the image to the contents of rb.
*/
public void setRect(Raster rb) {
int width = rb.getWidth();
int height = rb.getHeight();
int startX = rb.getMinX();
int startY = rb.getMinY();
int[] tdata = null;
// remind use get/setPixelPixelData for speed if Rasters are
// compatible
for (int i = startY; i < startY+height; i++) {
tdata = rb.getPixel(startX,i,width,1,tdata);
raster.setPixel(startX,i,width,1, tdata);
}
}
/** Forward work to a TileChangeMulticaster. */
public void addTileChangeListener (TileChangeListener tcl) {
tcm.addTileChangeListener(tcl);
}
/** Forward work to a TileChangeMulticaster. */
public void removeTileChangeListener (TileChangeListener tcl) {
tcm.removeTileChangeListener(tcl);
}
/** Forward work to a TileChangeMulticaster. */
public TileChangeListener[] getTileChangeListeners () {
return tcm.getTileChangeListeners();
}
/** Forward work to a TileChangeMulticaster. */
public boolean isTileWritable (int tileX, int tileY) {
return tcm.isTileWritable(tileX, tileY);
}
/** Forward work to a TileChangeMulticaster. */
public Point[] getWritableTiles () {
return tcm.getWritableTiles();
}
/** Forward work to a TileChangeMulticaster. */
public boolean hasTileWriters () {
return tcm.hasTileWriters();
}
public WritableRaster getWritableTile (int tileX, int tileY) {
tcm.addTileWriter(this, tileX, tileY);
return raster;
}
public void releaseWritableTile (int tileX, int tileY) {
tcm.removeTileWriter(this, tileX, tileY);
}
}