0001 /*
0002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.awt.image;
0027
0028 import java.awt.Transparency;
0029 import java.awt.color.ColorSpace;
0030 import java.awt.Graphics2D;
0031 import java.awt.GraphicsConfiguration;
0032 import java.awt.GraphicsEnvironment;
0033 import java.awt.ImageCapabilities;
0034 import java.awt.geom.Rectangle2D;
0035 import java.awt.geom.Point2D;
0036 import java.awt.Point;
0037 import java.awt.Rectangle;
0038 import java.util.Hashtable;
0039 import java.util.Vector;
0040
0041 import sun.awt.image.BytePackedRaster;
0042 import sun.awt.image.ShortComponentRaster;
0043 import sun.awt.image.ByteComponentRaster;
0044 import sun.awt.image.IntegerComponentRaster;
0045 import sun.awt.image.OffScreenImageSource;
0046
0047 /**
0048 *
0049 * The <code>BufferedImage</code> subclass describes an {@link
0050 * java.awt.Image Image} with an accessible buffer of image data.
0051 * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a
0052 * {@link Raster} of image data.
0053 * The number and types of bands in the {@link SampleModel} of the
0054 * <code>Raster</code> must match the number and types required by the
0055 * <code>ColorModel</code> to represent its color and alpha components.
0056 * All <code>BufferedImage</code> objects have an upper left corner
0057 * coordinate of (0, 0). Any <code>Raster</code> used to construct a
0058 * <code>BufferedImage</code> must therefore have minX=0 and minY=0.
0059 *
0060 * <p>
0061 * This class relies on the data fetching and setting methods
0062 * of <code>Raster</code>,
0063 * and on the color characterization methods of <code>ColorModel</code>.
0064 *
0065 * @see ColorModel
0066 * @see Raster
0067 * @see WritableRaster
0068 * @version 10 Feb 1997
0069 */
0070
0071 public class BufferedImage extends java.awt.Image implements
0072 WritableRenderedImage, Transparency {
0073 int imageType = TYPE_CUSTOM;
0074 ColorModel colorModel;
0075 WritableRaster raster;
0076 OffScreenImageSource osis;
0077 Hashtable properties;
0078
0079 boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in
0080 // color channels
0081
0082 /**
0083 * Image Type Constants
0084 */
0085
0086 /**
0087 * Image type is not recognized so it must be a customized
0088 * image. This type is only used as a return value for the getType()
0089 * method.
0090 */
0091 public static final int TYPE_CUSTOM = 0;
0092
0093 /**
0094 * Represents an image with 8-bit RGB color components packed into
0095 * integer pixels. The image has a {@link DirectColorModel} without
0096 * alpha.
0097 * When data with non-opaque alpha is stored
0098 * in an image of this type,
0099 * the color data must be adjusted to a non-premultiplied form
0100 * and the alpha discarded,
0101 * as described in the
0102 * {@link java.awt.AlphaComposite} documentation.
0103 */
0104 public static final int TYPE_INT_RGB = 1;
0105
0106 /**
0107 * Represents an image with 8-bit RGBA color components packed into
0108 * integer pixels. The image has a <code>DirectColorModel</code>
0109 * with alpha. The color data in this image is considered not to be
0110 * premultiplied with alpha. When this type is used as the
0111 * <code>imageType</code> argument to a <code>BufferedImage</code>
0112 * constructor, the created image is consistent with images
0113 * created in the JDK1.1 and earlier releases.
0114 */
0115 public static final int TYPE_INT_ARGB = 2;
0116
0117 /**
0118 * Represents an image with 8-bit RGBA color components packed into
0119 * integer pixels. The image has a <code>DirectColorModel</code>
0120 * with alpha. The color data in this image is considered to be
0121 * premultiplied with alpha.
0122 */
0123 public static final int TYPE_INT_ARGB_PRE = 3;
0124
0125 /**
0126 * Represents an image with 8-bit RGB color components, corresponding
0127 * to a Windows- or Solaris- style BGR color model, with the colors
0128 * Blue, Green, and Red packed into integer pixels. There is no alpha.
0129 * The image has a {@link DirectColorModel}.
0130 * When data with non-opaque alpha is stored
0131 * in an image of this type,
0132 * the color data must be adjusted to a non-premultiplied form
0133 * and the alpha discarded,
0134 * as described in the
0135 * {@link java.awt.AlphaComposite} documentation.
0136 */
0137 public static final int TYPE_INT_BGR = 4;
0138
0139 /**
0140 * Represents an image with 8-bit RGB color components, corresponding
0141 * to a Windows-style BGR color model) with the colors Blue, Green,
0142 * and Red stored in 3 bytes. There is no alpha. The image has a
0143 * <code>ComponentColorModel</code>.
0144 * When data with non-opaque alpha is stored
0145 * in an image of this type,
0146 * the color data must be adjusted to a non-premultiplied form
0147 * and the alpha discarded,
0148 * as described in the
0149 * {@link java.awt.AlphaComposite} documentation.
0150 */
0151 public static final int TYPE_3BYTE_BGR = 5;
0152
0153 /**
0154 * Represents an image with 8-bit RGBA color components with the colors
0155 * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
0156 * image has a <code>ComponentColorModel</code> with alpha. The
0157 * color data in this image is considered not to be premultiplied with
0158 * alpha. The byte data is interleaved in a single
0159 * byte array in the order A, B, G, R
0160 * from lower to higher byte addresses within each pixel.
0161 */
0162 public static final int TYPE_4BYTE_ABGR = 6;
0163
0164 /**
0165 * Represents an image with 8-bit RGBA color components with the colors
0166 * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
0167 * image has a <code>ComponentColorModel</code> with alpha. The color
0168 * data in this image is considered to be premultiplied with alpha.
0169 * The byte data is interleaved in a single byte array in the order
0170 * A, B, G, R from lower to higher byte addresses within each pixel.
0171 */
0172 public static final int TYPE_4BYTE_ABGR_PRE = 7;
0173
0174 /**
0175 * Represents an image with 5-6-5 RGB color components (5-bits red,
0176 * 6-bits green, 5-bits blue) with no alpha. This image has
0177 * a <code>DirectColorModel</code>.
0178 * When data with non-opaque alpha is stored
0179 * in an image of this type,
0180 * the color data must be adjusted to a non-premultiplied form
0181 * and the alpha discarded,
0182 * as described in the
0183 * {@link java.awt.AlphaComposite} documentation.
0184 */
0185 public static final int TYPE_USHORT_565_RGB = 8;
0186
0187 /**
0188 * Represents an image with 5-5-5 RGB color components (5-bits red,
0189 * 5-bits green, 5-bits blue) with no alpha. This image has
0190 * a <code>DirectColorModel</code>.
0191 * When data with non-opaque alpha is stored
0192 * in an image of this type,
0193 * the color data must be adjusted to a non-premultiplied form
0194 * and the alpha discarded,
0195 * as described in the
0196 * {@link java.awt.AlphaComposite} documentation.
0197 */
0198 public static final int TYPE_USHORT_555_RGB = 9;
0199
0200 /**
0201 * Represents a unsigned byte grayscale image, non-indexed. This
0202 * image has a <code>ComponentColorModel</code> with a CS_GRAY
0203 * {@link ColorSpace}.
0204 * When data with non-opaque alpha is stored
0205 * in an image of this type,
0206 * the color data must be adjusted to a non-premultiplied form
0207 * and the alpha discarded,
0208 * as described in the
0209 * {@link java.awt.AlphaComposite} documentation.
0210 */
0211 public static final int TYPE_BYTE_GRAY = 10;
0212
0213 /**
0214 * Represents an unsigned short grayscale image, non-indexed). This
0215 * image has a <code>ComponentColorModel</code> with a CS_GRAY
0216 * <code>ColorSpace</code>.
0217 * When data with non-opaque alpha is stored
0218 * in an image of this type,
0219 * the color data must be adjusted to a non-premultiplied form
0220 * and the alpha discarded,
0221 * as described in the
0222 * {@link java.awt.AlphaComposite} documentation.
0223 */
0224 public static final int TYPE_USHORT_GRAY = 11;
0225
0226 /**
0227 * Represents an opaque byte-packed 1, 2, or 4 bit image. The
0228 * image has an {@link IndexColorModel} without alpha. When this
0229 * type is used as the <code>imageType</code> argument to the
0230 * <code>BufferedImage</code> constructor that takes an
0231 * <code>imageType</code> argument but no <code>ColorModel</code>
0232 * argument, a 1-bit image is created with an
0233 * <code>IndexColorModel</code> with two colors in the default
0234 * sRGB <code>ColorSpace</code>: {0, 0, 0} and
0235 * {255, 255, 255}.
0236 *
0237 * <p> Images with 2 or 4 bits per pixel may be constructed via
0238 * the <code>BufferedImage</code> constructor that takes a
0239 * <code>ColorModel</code> argument by supplying a
0240 * <code>ColorModel</code> with an appropriate map size.
0241 *
0242 * <p> Images with 8 bits per pixel should use the image types
0243 * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code>
0244 * depending on their <code>ColorModel</code>.
0245
0246 * <p> When color data is stored in an image of this type,
0247 * the closest color in the colormap is determined
0248 * by the <code>IndexColorModel</code> and the resulting index is stored.
0249 * Approximation and loss of alpha or color components
0250 * can result, depending on the colors in the
0251 * <code>IndexColorModel</code> colormap.
0252 */
0253 public static final int TYPE_BYTE_BINARY = 12;
0254
0255 /**
0256 * Represents an indexed byte image. When this type is used as the
0257 * <code>imageType</code> argument to the <code>BufferedImage</code>
0258 * constructor that takes an <code>imageType</code> argument
0259 * but no <code>ColorModel</code> argument, an
0260 * <code>IndexColorModel</code> is created with
0261 * a 256-color 6/6/6 color cube palette with the rest of the colors
0262 * from 216-255 populated by grayscale values in the
0263 * default sRGB ColorSpace.
0264 *
0265 * <p> When color data is stored in an image of this type,
0266 * the closest color in the colormap is determined
0267 * by the <code>IndexColorModel</code> and the resulting index is stored.
0268 * Approximation and loss of alpha or color components
0269 * can result, depending on the colors in the
0270 * <code>IndexColorModel</code> colormap.
0271 */
0272 public static final int TYPE_BYTE_INDEXED = 13;
0273
0274 private static final int DCM_RED_MASK = 0x00ff0000;
0275 private static final int DCM_GREEN_MASK = 0x0000ff00;
0276 private static final int DCM_BLUE_MASK = 0x000000ff;
0277 private static final int DCM_ALPHA_MASK = 0xff000000;
0278 private static final int DCM_565_RED_MASK = 0xf800;
0279 private static final int DCM_565_GRN_MASK = 0x07E0;
0280 private static final int DCM_565_BLU_MASK = 0x001F;
0281 private static final int DCM_555_RED_MASK = 0x7C00;
0282 private static final int DCM_555_GRN_MASK = 0x03E0;
0283 private static final int DCM_555_BLU_MASK = 0x001F;
0284 private static final int DCM_BGR_RED_MASK = 0x0000ff;
0285 private static final int DCM_BGR_GRN_MASK = 0x00ff00;
0286 private static final int DCM_BGR_BLU_MASK = 0xff0000;
0287
0288 static private native void initIDs();
0289
0290 static {
0291 ColorModel.loadLibraries();
0292 initIDs();
0293 }
0294
0295 /**
0296 * Constructs a <code>BufferedImage</code> of one of the predefined
0297 * image types. The <code>ColorSpace</code> for the image is the
0298 * default sRGB space.
0299 * @param width width of the created image
0300 * @param height height of the created image
0301 * @param imageType type of the created image
0302 * @see ColorSpace
0303 * @see #TYPE_INT_RGB
0304 * @see #TYPE_INT_ARGB
0305 * @see #TYPE_INT_ARGB_PRE
0306 * @see #TYPE_INT_BGR
0307 * @see #TYPE_3BYTE_BGR
0308 * @see #TYPE_4BYTE_ABGR
0309 * @see #TYPE_4BYTE_ABGR_PRE
0310 * @see #TYPE_BYTE_GRAY
0311 * @see #TYPE_USHORT_GRAY
0312 * @see #TYPE_BYTE_BINARY
0313 * @see #TYPE_BYTE_INDEXED
0314 * @see #TYPE_USHORT_565_RGB
0315 * @see #TYPE_USHORT_555_RGB
0316 */
0317 public BufferedImage(int width, int height, int imageType) {
0318 switch (imageType) {
0319 case TYPE_INT_RGB: {
0320 colorModel = new DirectColorModel(24, 0x00ff0000, // Red
0321 0x0000ff00, // Green
0322 0x000000ff, // Blue
0323 0x0 // Alpha
0324 );
0325 raster = colorModel.createCompatibleWritableRaster(width,
0326 height);
0327 }
0328 break;
0329
0330 case TYPE_INT_ARGB: {
0331 colorModel = ColorModel.getRGBdefault();
0332
0333 raster = colorModel.createCompatibleWritableRaster(width,
0334 height);
0335 }
0336 break;
0337
0338 case TYPE_INT_ARGB_PRE: {
0339 colorModel = new DirectColorModel(ColorSpace
0340 .getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000,// Red
0341 0x0000ff00,// Green
0342 0x000000ff,// Blue
0343 0xff000000,// Alpha
0344 true, // Alpha Premultiplied
0345 DataBuffer.TYPE_INT);
0346
0347 raster = colorModel.createCompatibleWritableRaster(width,
0348 height);
0349 }
0350 break;
0351
0352 case TYPE_INT_BGR: {
0353 colorModel = new DirectColorModel(24, 0x000000ff, // Red
0354 0x0000ff00, // Green
0355 0x00ff0000 // Blue
0356 );
0357 raster = colorModel.createCompatibleWritableRaster(width,
0358 height);
0359 }
0360 break;
0361
0362 case TYPE_3BYTE_BGR: {
0363 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0364 int[] nBits = { 8, 8, 8 };
0365 int[] bOffs = { 2, 1, 0 };
0366 colorModel = new ComponentColorModel(cs, nBits, false,
0367 false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
0368 raster = Raster.createInterleavedRaster(
0369 DataBuffer.TYPE_BYTE, width, height, width * 3, 3,
0370 bOffs, null);
0371 }
0372 break;
0373
0374 case TYPE_4BYTE_ABGR: {
0375 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0376 int[] nBits = { 8, 8, 8, 8 };
0377 int[] bOffs = { 3, 2, 1, 0 };
0378 colorModel = new ComponentColorModel(cs, nBits, true,
0379 false, Transparency.TRANSLUCENT,
0380 DataBuffer.TYPE_BYTE);
0381 raster = Raster.createInterleavedRaster(
0382 DataBuffer.TYPE_BYTE, width, height, width * 4, 4,
0383 bOffs, null);
0384 }
0385 break;
0386
0387 case TYPE_4BYTE_ABGR_PRE: {
0388 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0389 int[] nBits = { 8, 8, 8, 8 };
0390 int[] bOffs = { 3, 2, 1, 0 };
0391 colorModel = new ComponentColorModel(cs, nBits, true, true,
0392 Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
0393 raster = Raster.createInterleavedRaster(
0394 DataBuffer.TYPE_BYTE, width, height, width * 4, 4,
0395 bOffs, null);
0396 }
0397 break;
0398
0399 case TYPE_BYTE_GRAY: {
0400 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
0401 int[] nBits = { 8 };
0402 colorModel = new ComponentColorModel(cs, nBits, false,
0403 true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
0404 raster = colorModel.createCompatibleWritableRaster(width,
0405 height);
0406 }
0407 break;
0408
0409 case TYPE_USHORT_GRAY: {
0410 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
0411 int[] nBits = { 16 };
0412 colorModel = new ComponentColorModel(cs, nBits, false,
0413 true, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
0414 raster = colorModel.createCompatibleWritableRaster(width,
0415 height);
0416 }
0417 break;
0418
0419 case TYPE_BYTE_BINARY: {
0420 byte[] arr = { (byte) 0, (byte) 0xff };
0421
0422 colorModel = new IndexColorModel(1, 2, arr, arr, arr);
0423 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
0424 width, height, 1, 1, null);
0425 }
0426 break;
0427
0428 case TYPE_BYTE_INDEXED: {
0429 // Create a 6x6x6 color cube
0430 int[] cmap = new int[256];
0431 int i = 0;
0432 for (int r = 0; r < 256; r += 51) {
0433 for (int g = 0; g < 256; g += 51) {
0434 for (int b = 0; b < 256; b += 51) {
0435 cmap[i++] = (r << 16) | (g << 8) | b;
0436 }
0437 }
0438 }
0439 // And populate the rest of the cmap with gray values
0440 int grayIncr = 256 / (256 - i);
0441
0442 // The gray ramp will be between 18 and 252
0443 int gray = grayIncr * 3;
0444 for (; i < 256; i++) {
0445 cmap[i] = (gray << 16) | (gray << 8) | gray;
0446 gray += grayIncr;
0447 }
0448
0449 colorModel = new IndexColorModel(8, 256, cmap, 0, false,
0450 -1, DataBuffer.TYPE_BYTE);
0451 raster = Raster.createInterleavedRaster(
0452 DataBuffer.TYPE_BYTE, width, height, 1, null);
0453 }
0454 break;
0455
0456 case TYPE_USHORT_565_RGB: {
0457 colorModel = new DirectColorModel(16, DCM_565_RED_MASK,
0458 DCM_565_GRN_MASK, DCM_565_BLU_MASK);
0459 raster = colorModel.createCompatibleWritableRaster(width,
0460 height);
0461 }
0462 break;
0463
0464 case TYPE_USHORT_555_RGB: {
0465 colorModel = new DirectColorModel(15, DCM_555_RED_MASK,
0466 DCM_555_GRN_MASK, DCM_555_BLU_MASK);
0467 raster = colorModel.createCompatibleWritableRaster(width,
0468 height);
0469 }
0470 break;
0471
0472 default:
0473 throw new IllegalArgumentException("Unknown image type "
0474 + imageType);
0475 }
0476
0477 this .imageType = imageType;
0478 }
0479
0480 /**
0481 * Constructs a <code>BufferedImage</code> of one of the predefined
0482 * image types:
0483 * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED.
0484 *
0485 * <p> If the image type is TYPE_BYTE_BINARY, the number of
0486 * entries in the color model is used to determine whether the
0487 * image should have 1, 2, or 4 bits per pixel. If the color model
0488 * has 1 or 2 entries, the image will have 1 bit per pixel. If it
0489 * has 3 or 4 entries, the image with have 2 bits per pixel. If
0490 * it has between 5 and 16 entries, the image will have 4 bits per
0491 * pixel. Otherwise, an IllegalArgumentException will be thrown.
0492 *
0493 * @param width width of the created image
0494 * @param height height of the created image
0495 * @param imageType type of the created image
0496 * @param cm <code>IndexColorModel</code> of the created image
0497 * @throws IllegalArgumentException if the imageType is not
0498 * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is
0499 * TYPE_BYTE_BINARY and the color map has more than 16 entries.
0500 * @see #TYPE_BYTE_BINARY
0501 * @see #TYPE_BYTE_INDEXED
0502 */
0503 public BufferedImage(int width, int height, int imageType,
0504 IndexColorModel cm) {
0505 if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
0506 throw new IllegalArgumentException(
0507 "This image types do not have "
0508 + "premultiplied alpha.");
0509 }
0510
0511 switch (imageType) {
0512 case TYPE_BYTE_BINARY:
0513 int bits; // Will be set below
0514 int mapSize = cm.getMapSize();
0515 if (mapSize <= 2) {
0516 bits = 1;
0517 } else if (mapSize <= 4) {
0518 bits = 2;
0519 } else if (mapSize <= 16) {
0520 bits = 4;
0521 } else {
0522 throw new IllegalArgumentException(
0523 "Color map for TYPE_BYTE_BINARY "
0524 + "must have no more than 16 entries");
0525 }
0526 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
0527 width, height, 1, bits, null);
0528 break;
0529
0530 case TYPE_BYTE_INDEXED:
0531 raster = Raster.createInterleavedRaster(
0532 DataBuffer.TYPE_BYTE, width, height, 1, null);
0533 break;
0534 default:
0535 throw new IllegalArgumentException("Invalid image type ("
0536 + imageType + "). Image type must"
0537 + " be either TYPE_BYTE_BINARY or "
0538 + " TYPE_BYTE_INDEXED");
0539 }
0540
0541 if (!cm.isCompatibleRaster(raster)) {
0542 throw new IllegalArgumentException(
0543 "Incompatible image type and IndexColorModel");
0544 }
0545
0546 colorModel = cm;
0547 this .imageType = imageType;
0548 }
0549
0550 /**
0551 * Constructs a new <code>BufferedImage</code> with a specified
0552 * <code>ColorModel</code> and <code>Raster</code>. If the number and
0553 * types of bands in the <code>SampleModel</code> of the
0554 * <code>Raster</code> do not match the number and types required by
0555 * the <code>ColorModel</code> to represent its color and alpha
0556 * components, a {@link RasterFormatException} is thrown. This
0557 * method can multiply or divide the color <code>Raster</code> data by
0558 * alpha to match the <code>alphaPremultiplied</code> state
0559 * in the <code>ColorModel</code>. Properties for this
0560 * <code>BufferedImage</code> can be established by passing
0561 * in a {@link Hashtable} of <code>String</code>/<code>Object</code>
0562 * pairs.
0563 * @param cm <code>ColorModel</code> for the new image
0564 * @param raster <code>Raster</code> for the image data
0565 * @param isRasterPremultiplied if <code>true</code>, the data in
0566 * the raster has been premultiplied with alpha.
0567 * @param properties <code>Hashtable</code> of
0568 * <code>String</code>/<code>Object</code> pairs.
0569 * @exception <code>RasterFormatException</code> if the number and
0570 * types of bands in the <code>SampleModel</code> of the
0571 * <code>Raster</code> do not match the number and types required by
0572 * the <code>ColorModel</code> to represent its color and alpha
0573 * components.
0574 * @exception <code>IllegalArgumentException</code> if
0575 * <code>raster</code> is incompatible with <code>cm</code>
0576 * @see ColorModel
0577 * @see Raster
0578 * @see WritableRaster
0579 */
0580
0581 /*
0582 *
0583 * FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
0584 * SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
0585 *
0586 */
0587 public BufferedImage(ColorModel cm, WritableRaster raster,
0588 boolean isRasterPremultiplied, Hashtable<?, ?> properties) {
0589
0590 if (!cm.isCompatibleRaster(raster)) {
0591 throw new IllegalArgumentException("Raster " + raster
0592 + " is incompatible with ColorModel " + cm);
0593 }
0594
0595 if ((raster.minX != 0) || (raster.minY != 0)) {
0596 throw new IllegalArgumentException("Raster " + raster
0597 + " has minX or minY not equal to zero: "
0598 + raster.minX + " " + raster.minY);
0599 }
0600
0601 colorModel = cm;
0602 this .raster = raster;
0603 this .properties = properties;
0604 int numBands = raster.getNumBands();
0605 boolean isAlphaPre = cm.isAlphaPremultiplied();
0606 ColorSpace cs;
0607
0608 // Force the raster data alpha state to match the premultiplied
0609 // state in the color model
0610 coerceData(isRasterPremultiplied);
0611
0612 SampleModel sm = raster.getSampleModel();
0613 cs = cm.getColorSpace();
0614 int csType = cs.getType();
0615 if (csType != ColorSpace.TYPE_RGB) {
0616 if (csType == ColorSpace.TYPE_GRAY
0617 && cm instanceof ComponentColorModel) {
0618 // Check if this might be a child raster (fix for bug 4240596)
0619 if (sm instanceof ComponentSampleModel
0620 && ((ComponentSampleModel) sm).getPixelStride() != numBands) {
0621 imageType = TYPE_CUSTOM;
0622 } else if (raster instanceof ByteComponentRaster
0623 && raster.getNumBands() == 1
0624 && cm.getComponentSize(0) == 8
0625 && ((ByteComponentRaster) raster)
0626 .getPixelStride() == 1) {
0627 imageType = TYPE_BYTE_GRAY;
0628 } else if (raster instanceof ShortComponentRaster
0629 && raster.getNumBands() == 1
0630 && cm.getComponentSize(0) == 16
0631 && ((ShortComponentRaster) raster)
0632 .getPixelStride() == 1) {
0633 imageType = TYPE_USHORT_GRAY;
0634 }
0635 } else {
0636 imageType = TYPE_CUSTOM;
0637 }
0638 return;
0639 }
0640
0641 if ((raster instanceof IntegerComponentRaster)
0642 && (numBands == 3 || numBands == 4)) {
0643 IntegerComponentRaster iraster = (IntegerComponentRaster) raster;
0644 // Check if the raster params and the color model
0645 // are correct
0646 int pixSize = cm.getPixelSize();
0647 if (iraster.getPixelStride() == 1
0648 && cm instanceof DirectColorModel
0649 && (pixSize == 32 || pixSize == 24)) {
0650 // Now check on the DirectColorModel params
0651 DirectColorModel dcm = (DirectColorModel) cm;
0652 int rmask = dcm.getRedMask();
0653 int gmask = dcm.getGreenMask();
0654 int bmask = dcm.getBlueMask();
0655 if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK
0656 && bmask == DCM_BLUE_MASK) {
0657 if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
0658 imageType = (isAlphaPre ? TYPE_INT_ARGB_PRE
0659 : TYPE_INT_ARGB);
0660 } else {
0661 // No Alpha
0662 if (!dcm.hasAlpha()) {
0663 imageType = TYPE_INT_RGB;
0664 }
0665 }
0666 } // if (dcm.getRedMask() == DCM_RED_MASK &&
0667 else if (rmask == DCM_BGR_RED_MASK
0668 && gmask == DCM_BGR_GRN_MASK
0669 && bmask == DCM_BGR_BLU_MASK) {
0670 if (!dcm.hasAlpha()) {
0671 imageType = TYPE_INT_BGR;
0672 }
0673 } // if (rmask == DCM_BGR_RED_MASK &&
0674 } // if (iraster.getPixelStride() == 1
0675 } // ((raster instanceof IntegerComponentRaster) &&
0676 else if ((cm instanceof IndexColorModel) && (numBands == 1)
0677 && (!cm.hasAlpha() || !isAlphaPre)) {
0678 IndexColorModel icm = (IndexColorModel) cm;
0679 int pixSize = icm.getPixelSize();
0680
0681 if (raster instanceof BytePackedRaster) {
0682 imageType = TYPE_BYTE_BINARY;
0683 } // if (raster instanceof BytePackedRaster)
0684 else if (raster instanceof ByteComponentRaster) {
0685 ByteComponentRaster braster = (ByteComponentRaster) raster;
0686 if (braster.getPixelStride() == 1 && pixSize <= 8) {
0687 imageType = TYPE_BYTE_INDEXED;
0688 }
0689 }
0690 } // else if (cm instanceof IndexColorModel) && (numBands == 1))
0691 else if ((raster instanceof ShortComponentRaster)
0692 && (cm instanceof DirectColorModel) && (numBands == 3)
0693 && !cm.hasAlpha()) {
0694 DirectColorModel dcm = (DirectColorModel) cm;
0695 if (dcm.getRedMask() == DCM_565_RED_MASK) {
0696 if (dcm.getGreenMask() == DCM_565_GRN_MASK
0697 && dcm.getBlueMask() == DCM_565_BLU_MASK) {
0698 imageType = TYPE_USHORT_565_RGB;
0699 }
0700 } else if (dcm.getRedMask() == DCM_555_RED_MASK) {
0701 if (dcm.getGreenMask() == DCM_555_GRN_MASK
0702 && dcm.getBlueMask() == DCM_555_BLU_MASK) {
0703 imageType = TYPE_USHORT_555_RGB;
0704 }
0705 }
0706 } // else if ((cm instanceof IndexColorModel) && (numBands == 1))
0707 else if ((raster instanceof ByteComponentRaster)
0708 && (cm instanceof ComponentColorModel)
0709 && (raster.getSampleModel() instanceof PixelInterleavedSampleModel)
0710 && (numBands == 3 || numBands == 4)) {
0711 ComponentColorModel ccm = (ComponentColorModel) cm;
0712 PixelInterleavedSampleModel csm = (PixelInterleavedSampleModel) raster
0713 .getSampleModel();
0714 ByteComponentRaster braster = (ByteComponentRaster) raster;
0715 int[] offs = csm.getBandOffsets();
0716 if (ccm.getNumComponents() != numBands) {
0717 throw new RasterFormatException(
0718 "Number of components in " + "ColorModel ("
0719 + ccm.getNumComponents()
0720 + ") does not match # in "
0721 + " Raster (" + numBands + ")");
0722 }
0723 int[] nBits = ccm.getComponentSize();
0724 boolean is8bit = true;
0725 for (int i = 0; i < numBands; i++) {
0726 if (nBits[i] != 8) {
0727 is8bit = false;
0728 break;
0729 }
0730 }
0731 if (is8bit && offs[0] == numBands - 1
0732 && offs[1] == numBands - 2
0733 && offs[2] == numBands - 3) {
0734 if (numBands == 3) {
0735 imageType = TYPE_3BYTE_BGR;
0736 } else if (offs[3] == 0) {
0737 imageType = (isAlphaPre ? TYPE_4BYTE_ABGR_PRE
0738 : TYPE_4BYTE_ABGR);
0739 }
0740 }
0741 } // else if ((raster instanceof ByteComponentRaster) &&
0742 }
0743
0744 /**
0745 * Returns the image type. If it is not one of the known types,
0746 * TYPE_CUSTOM is returned.
0747 * @return the image type of this <code>BufferedImage</code>.
0748 * @see #TYPE_INT_RGB
0749 * @see #TYPE_INT_ARGB
0750 * @see #TYPE_INT_ARGB_PRE
0751 * @see #TYPE_INT_BGR
0752 * @see #TYPE_3BYTE_BGR
0753 * @see #TYPE_4BYTE_ABGR
0754 * @see #TYPE_4BYTE_ABGR_PRE
0755 * @see #TYPE_BYTE_GRAY
0756 * @see #TYPE_BYTE_BINARY
0757 * @see #TYPE_BYTE_INDEXED
0758 * @see #TYPE_USHORT_GRAY
0759 * @see #TYPE_USHORT_565_RGB
0760 * @see #TYPE_USHORT_555_RGB
0761 * @see #TYPE_CUSTOM
0762 */
0763 public int getType() {
0764 return imageType;
0765 }
0766
0767 /**
0768 * Returns the <code>ColorModel</code>.
0769 * @return the <code>ColorModel</code> of this
0770 * <code>BufferedImage</code>.
0771 */
0772 public ColorModel getColorModel() {
0773 return colorModel;
0774 }
0775
0776 /**
0777 * Returns the {@link WritableRaster}.
0778 * @return the <code>WriteableRaster</code> of this
0779 * <code>BufferedImage</code>.
0780 */
0781 public WritableRaster getRaster() {
0782 return raster;
0783 }
0784
0785 /**
0786 * Returns a <code>WritableRaster</code> representing the alpha
0787 * channel for <code>BufferedImage</code> objects
0788 * with <code>ColorModel</code> objects that support a separate
0789 * spatial alpha channel, such as <code>ComponentColorModel</code> and
0790 * <code>DirectColorModel</code>. Returns <code>null</code> if there
0791 * is no alpha channel associated with the <code>ColorModel</code> in
0792 * this image. This method assumes that for all
0793 * <code>ColorModel</code> objects other than
0794 * <code>IndexColorModel</code>, if the <code>ColorModel</code>
0795 * supports alpha, there is a separate alpha channel
0796 * which is stored as the last band of image data.
0797 * If the image uses an <code>IndexColorModel</code> that
0798 * has alpha in the lookup table, this method returns
0799 * <code>null</code> since there is no spatially discrete alpha
0800 * channel. This method creates a new
0801 * <code>WritableRaster</code>, but shares the data array.
0802 * @return a <code>WritableRaster</code> or <code>null</code> if this
0803 * <code>BufferedImage</code> has no alpha channel associated
0804 * with its <code>ColorModel</code>.
0805 */
0806 public WritableRaster getAlphaRaster() {
0807 return colorModel.getAlphaRaster(raster);
0808 }
0809
0810 /**
0811 * Returns an integer pixel in the default RGB color model
0812 * (TYPE_INT_ARGB) and default sRGB colorspace. Color
0813 * conversion takes place if this default model does not match
0814 * the image <code>ColorModel</code>. There are only 8-bits of
0815 * precision for each color component in the returned data when using
0816 * this method.
0817 *
0818 * <p>
0819 *
0820 * An <code>ArrayOutOfBoundsException</code> may be thrown
0821 * if the coordinates are not in bounds.
0822 * However, explicit bounds checking is not guaranteed.
0823 *
0824 * @param x the X coordinate of the pixel from which to get
0825 * the pixel in the default RGB color model and sRGB
0826 * color space
0827 * @param y the Y coordinate of the pixel from which to get
0828 * the pixel in the default RGB color model and sRGB
0829 * color space
0830 * @return an integer pixel in the default RGB color model and
0831 * default sRGB colorspace.
0832 * @see #setRGB(int, int, int)
0833 * @see #setRGB(int, int, int, int, int[], int, int)
0834 */
0835 public int getRGB(int x, int y) {
0836 return colorModel.getRGB(raster.getDataElements(x, y, null));
0837 }
0838
0839 /**
0840 * Returns an array of integer pixels in the default RGB color model
0841 * (TYPE_INT_ARGB) and default sRGB color space,
0842 * from a portion of the image data. Color conversion takes
0843 * place if the default model does not match the image
0844 * <code>ColorModel</code>. There are only 8-bits of precision for
0845 * each color component in the returned data when
0846 * using this method. With a specified coordinate (x, y) in the
0847 * image, the ARGB pixel can be accessed in this way:
0848 * </p>
0849 *
0850 * <pre>
0851 * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre>
0852 *
0853 * <p>
0854 *
0855 * An <code>ArrayOutOfBoundsException</code> may be thrown
0856 * if the region is not in bounds.
0857 * However, explicit bounds checking is not guaranteed.
0858 *
0859 * @param startX the starting X coordinate
0860 * @param startY the starting Y coordinate
0861 * @param w width of region
0862 * @param h height of region
0863 * @param rgbArray if not <code>null</code>, the rgb pixels are
0864 * written here
0865 * @param offset offset into the <code>rgbArray</code>
0866 * @param scansize scanline stride for the <code>rgbArray</code>
0867 * @return array of RGB pixels.
0868 * @see #setRGB(int, int, int)
0869 * @see #setRGB(int, int, int, int, int[], int, int)
0870 */
0871 public int[] getRGB(int startX, int startY, int w, int h,
0872 int[] rgbArray, int offset, int scansize) {
0873 int yoff = offset;
0874 int off;
0875 Object data;
0876 int nbands = raster.getNumBands();
0877 int dataType = raster.getDataBuffer().getDataType();
0878 switch (dataType) {
0879 case DataBuffer.TYPE_BYTE:
0880 data = new byte[nbands];
0881 break;
0882 case DataBuffer.TYPE_USHORT:
0883 data = new short[nbands];
0884 break;
0885 case DataBuffer.TYPE_INT:
0886 data = new int[nbands];
0887 break;
0888 case DataBuffer.TYPE_FLOAT:
0889 data = new float[nbands];
0890 break;
0891 case DataBuffer.TYPE_DOUBLE:
0892 data = new double[nbands];
0893 break;
0894 default:
0895 throw new IllegalArgumentException(
0896 "Unknown data buffer type: " + dataType);
0897 }
0898
0899 if (rgbArray == null) {
0900 rgbArray = new int[offset + h * scansize];
0901 }
0902
0903 for (int y = startY; y < startY + h; y++, yoff += scansize) {
0904 off = yoff;
0905 for (int x = startX; x < startX + w; x++) {
0906 rgbArray[off++] = colorModel.getRGB(raster
0907 .getDataElements(x, y, data));
0908 }
0909 }
0910
0911 return rgbArray;
0912 }
0913
0914 /**
0915 * Sets a pixel in this <code>BufferedImage</code> to the specified
0916 * RGB value. The pixel is assumed to be in the default RGB color
0917 * model, TYPE_INT_ARGB, and default sRGB color space. For images
0918 * with an <code>IndexColorModel</code>, the index with the nearest
0919 * color is chosen.
0920 *
0921 * <p>
0922 *
0923 * An <code>ArrayOutOfBoundsException</code> may be thrown
0924 * if the coordinates are not in bounds.
0925 * However, explicit bounds checking is not guaranteed.
0926 *
0927 * @param x the X coordinate of the pixel to set
0928 * @param y the Y coordinate of the pixel to set
0929 * @param rgb the RGB value
0930 * @see #getRGB(int, int)
0931 * @see #getRGB(int, int, int, int, int[], int, int)
0932 */
0933 public synchronized void setRGB(int x, int y, int rgb) {
0934 raster.setDataElements(x, y, colorModel.getDataElements(rgb,
0935 null));
0936 }
0937
0938 /**
0939 * Sets an array of integer pixels in the default RGB color model
0940 * (TYPE_INT_ARGB) and default sRGB color space,
0941 * into a portion of the image data. Color conversion takes place
0942 * if the default model does not match the image
0943 * <code>ColorModel</code>. There are only 8-bits of precision for
0944 * each color component in the returned data when
0945 * using this method. With a specified coordinate (x, y) in the
0946 * this image, the ARGB pixel can be accessed in this way:
0947 * <pre>
0948 * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
0949 * </pre>
0950 * WARNING: No dithering takes place.
0951 *
0952 * <p>
0953 *
0954 * An <code>ArrayOutOfBoundsException</code> may be thrown
0955 * if the region is not in bounds.
0956 * However, explicit bounds checking is not guaranteed.
0957 *
0958 * @param startX the starting X coordinate
0959 * @param startY the starting Y coordinate
0960 * @param w width of the region
0961 * @param h height of the region
0962 * @param rgbArray the rgb pixels
0963 * @param offset offset into the <code>rgbArray</code>
0964 * @param scansize scanline stride for the <code>rgbArray</code>
0965 * @see #getRGB(int, int)
0966 * @see #getRGB(int, int, int, int, int[], int, int)
0967 */
0968 public void setRGB(int startX, int startY, int w, int h,
0969 int[] rgbArray, int offset, int scansize) {
0970 int yoff = offset;
0971 int off;
0972 Object pixel = null;
0973
0974 for (int y = startY; y < startY + h; y++, yoff += scansize) {
0975 off = yoff;
0976 for (int x = startX; x < startX + w; x++) {
0977 pixel = colorModel.getDataElements(rgbArray[off++],
0978 pixel);
0979 raster.setDataElements(x, y, pixel);
0980 }
0981 }
0982 }
0983
0984 /**
0985 * Returns the width of the <code>BufferedImage</code>.
0986 * @return the width of this <code>BufferedImage</code>
0987 */
0988 public int getWidth() {
0989 return raster.getWidth();
0990 }
0991
0992 /**
0993 * Returns the height of the <code>BufferedImage</code>.
0994 * @return the height of this <code>BufferedImage</code>
0995 */
0996 public int getHeight() {
0997 return raster.getHeight();
0998 }
0999
1000 /**
1001 * Returns the width of the <code>BufferedImage</code>.
1002 * @param observer ignored
1003 * @return the width of this <code>BufferedImage</code>
1004 */
1005 public int getWidth(ImageObserver observer) {
1006 return raster.getWidth();
1007 }
1008
1009 /**
1010 * Returns the height of the <code>BufferedImage</code>.
1011 * @param observer ignored
1012 * @return the height of this <code>BufferedImage</code>
1013 */
1014 public int getHeight(ImageObserver observer) {
1015 return raster.getHeight();
1016 }
1017
1018 /**
1019 * Returns the object that produces the pixels for the image.
1020 * @return the {@link ImageProducer} that is used to produce the
1021 * pixels for this image.
1022 * @see ImageProducer
1023 */
1024 public ImageProducer getSource() {
1025 if (osis == null) {
1026 if (properties == null) {
1027 properties = new Hashtable();
1028 }
1029 osis = new OffScreenImageSource(this , properties);
1030 }
1031 return osis;
1032 }
1033
1034 /**
1035 * Returns a property of the image by name. Individual property names
1036 * are defined by the various image formats. If a property is not
1037 * defined for a particular image, this method returns the
1038 * <code>UndefinedProperty</code> field. If the properties
1039 * for this image are not yet known, then this method returns
1040 * <code>null</code> and the <code>ImageObserver</code> object is
1041 * notified later. The property name "comment" should be used to
1042 * store an optional comment that can be presented to the user as a
1043 * description of the image, its source, or its author.
1044 * @param name the property name
1045 * @param observer the <code>ImageObserver</code> that receives
1046 * notification regarding image information
1047 * @return an {@link Object} that is the property referred to by the
1048 * specified <code>name</code> or <code>null</code> if the
1049 * properties of this image are not yet known.
1050 * @throws <code>NullPointerException</code> if the property name is null.
1051 * @see ImageObserver
1052 * @see java.awt.Image#UndefinedProperty
1053 */
1054 public Object getProperty(String name, ImageObserver observer) {
1055 return getProperty(name);
1056 }
1057
1058 /**
1059 * Returns a property of the image by name.
1060 * @param name the property name
1061 * @return an <code>Object</code> that is the property referred to by
1062 * the specified <code>name</code>.
1063 * @throws <code>NullPointerException</code> if the property name is null.
1064 */
1065 public Object getProperty(String name) {
1066 if (name == null) {
1067 throw new NullPointerException(
1068 "null property name is not allowed");
1069 }
1070 if (properties == null) {
1071 return java.awt.Image.UndefinedProperty;
1072 }
1073 Object o = properties.get(name);
1074 if (o == null) {
1075 o = java.awt.Image.UndefinedProperty;
1076 }
1077 return o;
1078 }
1079
1080 /**
1081 * This method returns a {@link Graphics2D}, but is here
1082 * for backwards compatibility. {@link #createGraphics() createGraphics} is more
1083 * convenient, since it is declared to return a
1084 * <code>Graphics2D</code>.
1085 * @return a <code>Graphics2D</code>, which can be used to draw into
1086 * this image.
1087 */
1088 public java.awt.Graphics getGraphics() {
1089 return createGraphics();
1090 }
1091
1092 /**
1093 * Creates a <code>Graphics2D</code>, which can be used to draw into
1094 * this <code>BufferedImage</code>.
1095 * @return a <code>Graphics2D</code>, used for drawing into this
1096 * image.
1097 */
1098 public Graphics2D createGraphics() {
1099 GraphicsEnvironment env = GraphicsEnvironment
1100 .getLocalGraphicsEnvironment();
1101 return env.createGraphics(this );
1102 }
1103
1104 /**
1105 * Returns a subimage defined by a specified rectangular region.
1106 * The returned <code>BufferedImage</code> shares the same
1107 * data array as the original image.
1108 * @param x the X coordinate of the upper-left corner of the
1109 * specified rectangular region
1110 * @param y the Y coordinate of the upper-left corner of the
1111 * specified rectangular region
1112 * @param w the width of the specified rectangular region
1113 * @param h the height of the specified rectangular region
1114 * @return a <code>BufferedImage</code> that is the subimage of this
1115 * <code>BufferedImage</code>.
1116 * @exception <code>RasterFormatException</code> if the specified
1117 * area is not contained within this <code>BufferedImage</code>.
1118 */
1119 public BufferedImage getSubimage(int x, int y, int w, int h) {
1120 return new BufferedImage(colorModel, raster
1121 .createWritableChild(x, y, w, h, 0, 0, null),
1122 colorModel.isAlphaPremultiplied(), properties);
1123 }
1124
1125 /**
1126 * Returns whether or not the alpha has been premultiplied. It
1127 * returns <code>false</code> if there is no alpha.
1128 * @return <code>true</code> if the alpha has been premultiplied;
1129 * <code>false</code> otherwise.
1130 */
1131 public boolean isAlphaPremultiplied() {
1132 return colorModel.isAlphaPremultiplied();
1133 }
1134
1135 /**
1136 * Forces the data to match the state specified in the
1137 * <code>isAlphaPremultiplied</code> variable. It may multiply or
1138 * divide the color raster data by alpha, or do nothing if the data is
1139 * in the correct state.
1140 * @param isAlphaPremultiplied <code>true</code> if the alpha has been
1141 * premultiplied; <code>false</code> otherwise.
1142 */
1143 public void coerceData(boolean isAlphaPremultiplied) {
1144 if (colorModel.hasAlpha()
1145 && colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
1146 // Make the color model do the conversion
1147 colorModel = colorModel.coerceData(raster,
1148 isAlphaPremultiplied);
1149 }
1150 }
1151
1152 /**
1153 * Returns a <code>String</code> representation of this
1154 * <code>BufferedImage</code> object and its values.
1155 * @return a <code>String</code> representing this
1156 * <code>BufferedImage</code>.
1157 */
1158 public String toString() {
1159 return new String("BufferedImage@"
1160 + Integer.toHexString(hashCode()) + ": type = "
1161 + imageType + " " + colorModel + " " + raster);
1162 }
1163
1164 /**
1165 * Returns a {@link Vector} of {@link RenderedImage} objects that are
1166 * the immediate sources, not the sources of these immediate sources,
1167 * of image data for this <code>BufferedImage</code>. This
1168 * method returns <code>null</code> if the <code>BufferedImage</code>
1169 * has no information about its immediate sources. It returns an
1170 * empty <code>Vector</code> if the <code>BufferedImage</code> has no
1171 * immediate sources.
1172 * @return a <code>Vector</code> containing immediate sources of
1173 * this <code>BufferedImage</code> object's image date, or
1174 * <code>null</code> if this <code>BufferedImage</code> has
1175 * no information about its immediate sources, or an empty
1176 * <code>Vector</code> if this <code>BufferedImage</code>
1177 * has no immediate sources.
1178 */
1179 public Vector<RenderedImage> getSources() {
1180 return null;
1181 }
1182
1183 /**
1184 * Returns an array of names recognized by
1185 * {@link #getProperty(String) getProperty(String)}
1186 * or <code>null</code>, if no property names are recognized.
1187 * @return a <code>String</code> array containing all of the property
1188 * names that <code>getProperty(String)</code> recognizes;
1189 * or <code>null</code> if no property names are recognized.
1190 */
1191 public String[] getPropertyNames() {
1192 return null;
1193 }
1194
1195 /**
1196 * Returns the minimum x coordinate of this
1197 * <code>BufferedImage</code>. This is always zero.
1198 * @return the minimum x coordinate of this
1199 * <code>BufferedImage</code>.
1200 */
1201 public int getMinX() {
1202 return raster.getMinX();
1203 }
1204
1205 /**
1206 * Returns the minimum y coordinate of this
1207 * <code>BufferedImage</code>. This is always zero.
1208 * @return the minimum y coordinate of this
1209 * <code>BufferedImage</code>.
1210 */
1211 public int getMinY() {
1212 return raster.getMinY();
1213 }
1214
1215 /**
1216 * Returns the <code>SampleModel</code> associated with this
1217 * <code>BufferedImage</code>.
1218 * @return the <code>SampleModel</code> of this
1219 * <code>BufferedImage</code>.
1220 */
1221 public SampleModel getSampleModel() {
1222 return raster.getSampleModel();
1223 }
1224
1225 /**
1226 * Returns the number of tiles in the x direction.
1227 * This is always one.
1228 * @return the number of tiles in the x direction.
1229 */
1230 public int getNumXTiles() {
1231 return 1;
1232 }
1233
1234 /**
1235 * Returns the number of tiles in the y direction.
1236 * This is always one.
1237 * @return the number of tiles in the y direction.
1238 */
1239 public int getNumYTiles() {
1240 return 1;
1241 }
1242
1243 /**
1244 * Returns the minimum tile index in the x direction.
1245 * This is always zero.
1246 * @return the minimum tile index in the x direction.
1247 */
1248 public int getMinTileX() {
1249 return 0;
1250 }
1251
1252 /**
1253 * Returns the minimum tile index in the y direction.
1254 * This is always zero.
1255 * @return the mininum tile index in the y direction.
1256 */
1257 public int getMinTileY() {
1258 return 0;
1259 }
1260
1261 /**
1262 * Returns the tile width in pixels.
1263 * @return the tile width in pixels.
1264 */
1265 public int getTileWidth() {
1266 return raster.getWidth();
1267 }
1268
1269 /**
1270 * Returns the tile height in pixels.
1271 * @return the tile height in pixels.
1272 */
1273 public int getTileHeight() {
1274 return raster.getHeight();
1275 }
1276
1277 /**
1278 * Returns the x offset of the tile grid relative to the origin,
1279 * For example, the x coordinate of the location of tile
1280 * (0, 0). This is always zero.
1281 * @return the x offset of the tile grid.
1282 */
1283 public int getTileGridXOffset() {
1284 return raster.getSampleModelTranslateX();
1285 }
1286
1287 /**
1288 * Returns the y offset of the tile grid relative to the origin,
1289 * For example, the y coordinate of the location of tile
1290 * (0, 0). This is always zero.
1291 * @return the y offset of the tile grid.
1292 */
1293 public int getTileGridYOffset() {
1294 return raster.getSampleModelTranslateY();
1295 }
1296
1297 /**
1298 * Returns tile (<code>tileX</code>, <code>tileY</code>). Note
1299 * that <code>tileX</code> and <code>tileY</code> are indices
1300 * into the tile array, not pixel locations. The <code>Raster</code>
1301 * that is returned is live, which means that it is updated if the
1302 * image is changed.
1303 * @param tileX the x index of the requested tile in the tile array
1304 * @param tileY the y index of the requested tile in the tile array
1305 * @return a <code>Raster</code> that is the tile defined by the
1306 * arguments <code>tileX</code> and <code>tileY</code>.
1307 * @exception <code>ArrayIndexOutOfBoundsException</code> if both
1308 * <code>tileX</code> and <code>tileY</code> are not
1309 * equal to 0
1310 */
1311 public Raster getTile(int tileX, int tileY) {
1312 if (tileX == 0 && tileY == 0) {
1313 return raster;
1314 }
1315 throw new ArrayIndexOutOfBoundsException(
1316 "BufferedImages only have" + " one tile with index 0,0");
1317 }
1318
1319 /**
1320 * Returns the image as one large tile. The <code>Raster</code>
1321 * returned is a copy of the image data is not updated if the
1322 * image is changed.
1323 * @return a <code>Raster</code> that is a copy of the image data.
1324 * @see #setData(Raster)
1325 */
1326 public Raster getData() {
1327
1328 // REMIND : this allocates a whole new tile if raster is a
1329 // subtile. (It only copies in the requested area)
1330 // We should do something smarter.
1331 int width = raster.getWidth();
1332 int height = raster.getHeight();
1333 int startX = raster.getMinX();
1334 int startY = raster.getMinY();
1335 WritableRaster wr = Raster.createWritableRaster(raster
1336 .getSampleModel(), new Point(raster
1337 .getSampleModelTranslateX(), raster
1338 .getSampleModelTranslateY()));
1339
1340 Object tdata = null;
1341
1342 for (int i = startY; i < startY + height; i++) {
1343 tdata = raster.getDataElements(startX, i, width, 1, tdata);
1344 wr.setDataElements(startX, i, width, 1, tdata);
1345 }
1346 return wr;
1347 }
1348
1349 /**
1350 * Computes and returns an arbitrary region of the
1351 * <code>BufferedImage</code>. The <code>Raster</code> returned is a
1352 * copy of the image data and is not updated if the image is
1353 * changed.
1354 * @param rect the region of the <code>BufferedImage</code> to be
1355 * returned.
1356 * @return a <code>Raster</code> that is a copy of the image data of
1357 * the specified region of the <code>BufferedImage</code>
1358 * @see #setData(Raster)
1359 */
1360 public Raster getData(Rectangle rect) {
1361 SampleModel sm = raster.getSampleModel();
1362 SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
1363 rect.height);
1364 WritableRaster wr = Raster.createWritableRaster(nsm, rect
1365 .getLocation());
1366 int width = rect.width;
1367 int height = rect.height;
1368 int startX = rect.x;
1369 int startY = rect.y;
1370
1371 Object tdata = null;
1372
1373 for (int i = startY; i < startY + height; i++) {
1374 tdata = raster.getDataElements(startX, i, width, 1, tdata);
1375 wr.setDataElements(startX, i, width, 1, tdata);
1376 }
1377 return wr;
1378 }
1379
1380 /**
1381 * Computes an arbitrary rectangular region of the
1382 * <code>BufferedImage</code> and copies it into a specified
1383 * <code>WritableRaster</code>. The region to be computed is
1384 * determined from the bounds of the specified
1385 * <code>WritableRaster</code>. The specified
1386 * <code>WritableRaster</code> must have a
1387 * <code>SampleModel</code> that is compatible with this image. If
1388 * <code>outRaster</code> is <code>null</code>,
1389 * an appropriate <code>WritableRaster</code> is created.
1390 * @param outRaster a <code>WritableRaster</code> to hold the returned
1391 * part of the image, or <code>null</code>
1392 * @return a reference to the supplied or created
1393 * <code>WritableRaster</code>.
1394 */
1395 public WritableRaster copyData(WritableRaster outRaster) {
1396 if (outRaster == null) {
1397 return (WritableRaster) getData();
1398 }
1399 int width = outRaster.getWidth();
1400 int height = outRaster.getHeight();
1401 int startX = outRaster.getMinX();
1402 int startY = outRaster.getMinY();
1403
1404 Object tdata = null;
1405
1406 for (int i = startY; i < startY + height; i++) {
1407 tdata = raster.getDataElements(startX, i, width, 1, tdata);
1408 outRaster.setDataElements(startX, i, width, 1, tdata);
1409 }
1410
1411 return outRaster;
1412 }
1413
1414 /**
1415 * Sets a rectangular region of the image to the contents of the
1416 * specified <code>Raster</code> <code>r</code>, which is
1417 * assumed to be in the same coordinate space as the
1418 * <code>BufferedImage</code>. The operation is clipped to the bounds
1419 * of the <code>BufferedImage</code>.
1420 * @param r the specified <code>Raster</code>
1421 * @see #getData
1422 * @see #getData(Rectangle)
1423 */
1424 public void setData(Raster r) {
1425 int width = r.getWidth();
1426 int height = r.getHeight();
1427 int startX = r.getMinX();
1428 int startY = r.getMinY();
1429
1430 int[] tdata = null;
1431
1432 // Clip to the current Raster
1433 Rectangle rclip = new Rectangle(startX, startY, width, height);
1434 Rectangle bclip = new Rectangle(0, 0, raster.width,
1435 raster.height);
1436 Rectangle intersect = rclip.intersection(bclip);
1437 if (intersect.isEmpty()) {
1438 return;
1439 }
1440 width = intersect.width;
1441 height = intersect.height;
1442 startX = intersect.x;
1443 startY = intersect.y;
1444
1445 // remind use get/setDataElements for speed if Rasters are
1446 // compatible
1447 for (int i = startY; i < startY + height; i++) {
1448 tdata = r.getPixels(startX, i, width, 1, tdata);
1449 raster.setPixels(startX, i, width, 1, tdata);
1450 }
1451 }
1452
1453 /**
1454 * Adds a tile observer. If the observer is already present,
1455 * it receives multiple notifications.
1456 * @param to the specified {@link TileObserver}
1457 */
1458 public void addTileObserver(TileObserver to) {
1459 }
1460
1461 /**
1462 * Removes a tile observer. If the observer was not registered,
1463 * nothing happens. If the observer was registered for multiple
1464 * notifications, it is now registered for one fewer notification.
1465 * @param to the specified <code>TileObserver</code>.
1466 */
1467 public void removeTileObserver(TileObserver to) {
1468 }
1469
1470 /**
1471 * Returns whether or not a tile is currently checked out for writing.
1472 * @param tileX the x index of the tile.
1473 * @param tileY the y index of the tile.
1474 * @return <code>true</code> if the tile specified by the specified
1475 * indices is checked out for writing; <code>false</code>
1476 * otherwise.
1477 * @exception <code>ArrayIndexOutOfBoundsException</code> if both
1478 * <code>tileX</code> and <code>tileY</code> are not equal
1479 * to 0
1480 */
1481 public boolean isTileWritable(int tileX, int tileY) {
1482 if (tileX == 0 && tileY == 0) {
1483 return true;
1484 }
1485 throw new IllegalArgumentException("Only 1 tile in image");
1486 }
1487
1488 /**
1489 * Returns an array of {@link Point} objects indicating which tiles
1490 * are checked out for writing. Returns <code>null</code> if none are
1491 * checked out.
1492 * @return a <code>Point</code> array that indicates the tiles that
1493 * are checked out for writing, or <code>null</code> if no
1494 * tiles are checked out for writing.
1495 */
1496 public Point[] getWritableTileIndices() {
1497 Point[] p = new Point[1];
1498 p[0] = new Point(0, 0);
1499
1500 return p;
1501 }
1502
1503 /**
1504 * Returns whether or not any tile is checked out for writing.
1505 * Semantically equivalent to
1506 * <pre>
1507 * (getWritableTileIndices() != null).
1508 * </pre>
1509 * @return <code>true</code> if any tile is checked out for writing;
1510 * <code>false</code> otherwise.
1511 */
1512 public boolean hasTileWriters() {
1513 return true;
1514 }
1515
1516 /**
1517 * Checks out a tile for writing. All registered
1518 * <code>TileObservers</code> are notified when a tile goes from having
1519 * no writers to having one writer.
1520 * @param tileX the x index of the tile
1521 * @param tileY the y index of the tile
1522 * @return a <code>WritableRaster</code> that is the tile, indicated by
1523 * the specified indices, to be checked out for writing.
1524 */
1525 public WritableRaster getWritableTile(int tileX, int tileY) {
1526 return raster;
1527 }
1528
1529 /**
1530 * Relinquishes permission to write to a tile. If the caller
1531 * continues to write to the tile, the results are undefined.
1532 * Calls to this method should only appear in matching pairs
1533 * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}. Any other leads
1534 * to undefined results. All registered <code>TileObservers</code>
1535 * are notified when a tile goes from having one writer to having no
1536 * writers.
1537 * @param tileX the x index of the tile
1538 * @param tileY the y index of the tile
1539 */
1540 public void releaseWritableTile(int tileX, int tileY) {
1541 }
1542
1543 /**
1544 * Returns the transparency. Returns either OPAQUE, BITMASK,
1545 * or TRANSLUCENT.
1546 * @return the transparency of this <code>BufferedImage</code>.
1547 * @see Transparency#OPAQUE
1548 * @see Transparency#BITMASK
1549 * @see Transparency#TRANSLUCENT
1550 * @since 1.5
1551 */
1552 public int getTransparency() {
1553 return colorModel.getTransparency();
1554 }
1555 }
|