0N/A/*
2362N/A * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.awt.image;
0N/A
0N/Aimport java.awt.Transparency;
0N/Aimport java.awt.color.ColorSpace;
0N/Aimport java.awt.Graphics2D;
0N/Aimport java.awt.GraphicsConfiguration;
0N/Aimport java.awt.GraphicsEnvironment;
0N/Aimport java.awt.ImageCapabilities;
0N/Aimport java.awt.geom.Rectangle2D;
0N/Aimport java.awt.geom.Point2D;
0N/Aimport java.awt.Point;
0N/Aimport java.awt.Rectangle;
6395N/Aimport java.security.AccessController;
6395N/Aimport java.security.PrivilegedAction;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Vector;
0N/A
0N/Aimport sun.awt.image.BytePackedRaster;
0N/Aimport sun.awt.image.ShortComponentRaster;
0N/Aimport sun.awt.image.ByteComponentRaster;
0N/Aimport sun.awt.image.IntegerComponentRaster;
0N/Aimport sun.awt.image.OffScreenImageSource;
0N/A
0N/A/**
0N/A *
0N/A * The <code>BufferedImage</code> subclass describes an {@link
0N/A * java.awt.Image Image} with an accessible buffer of image data.
0N/A * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a
0N/A * {@link Raster} of image data.
0N/A * The number and types of bands in the {@link SampleModel} of the
0N/A * <code>Raster</code> must match the number and types required by the
0N/A * <code>ColorModel</code> to represent its color and alpha components.
0N/A * All <code>BufferedImage</code> objects have an upper left corner
0N/A * coordinate of (0,&nbsp;0). Any <code>Raster</code> used to construct a
0N/A * <code>BufferedImage</code> must therefore have minX=0 and minY=0.
0N/A *
0N/A * <p>
0N/A * This class relies on the data fetching and setting methods
0N/A * of <code>Raster</code>,
0N/A * and on the color characterization methods of <code>ColorModel</code>.
0N/A *
0N/A * @see ColorModel
0N/A * @see Raster
0N/A * @see WritableRaster
0N/A */
0N/A
0N/Apublic class BufferedImage extends java.awt.Image
0N/A implements WritableRenderedImage, Transparency
0N/A{
0N/A int imageType = TYPE_CUSTOM;
0N/A ColorModel colorModel;
0N/A WritableRaster raster;
0N/A OffScreenImageSource osis;
0N/A Hashtable properties;
0N/A
0N/A boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in
0N/A // color channels
0N/A
0N/A /**
0N/A * Image Type Constants
0N/A */
0N/A
0N/A /**
0N/A * Image type is not recognized so it must be a customized
0N/A * image. This type is only used as a return value for the getType()
0N/A * method.
0N/A */
0N/A public static final int TYPE_CUSTOM = 0;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGB color components packed into
0N/A * integer pixels. The image has a {@link DirectColorModel} without
0N/A * alpha.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_INT_RGB = 1;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGBA color components packed into
0N/A * integer pixels. The image has a <code>DirectColorModel</code>
0N/A * with alpha. The color data in this image is considered not to be
0N/A * premultiplied with alpha. When this type is used as the
0N/A * <code>imageType</code> argument to a <code>BufferedImage</code>
0N/A * constructor, the created image is consistent with images
0N/A * created in the JDK1.1 and earlier releases.
0N/A */
0N/A public static final int TYPE_INT_ARGB = 2;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGBA color components packed into
0N/A * integer pixels. The image has a <code>DirectColorModel</code>
0N/A * with alpha. The color data in this image is considered to be
0N/A * premultiplied with alpha.
0N/A */
0N/A public static final int TYPE_INT_ARGB_PRE = 3;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGB color components, corresponding
0N/A * to a Windows- or Solaris- style BGR color model, with the colors
0N/A * Blue, Green, and Red packed into integer pixels. There is no alpha.
0N/A * The image has a {@link DirectColorModel}.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_INT_BGR = 4;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGB color components, corresponding
0N/A * to a Windows-style BGR color model) with the colors Blue, Green,
0N/A * and Red stored in 3 bytes. There is no alpha. The image has a
0N/A * <code>ComponentColorModel</code>.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_3BYTE_BGR = 5;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGBA color components with the colors
0N/A * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
0N/A * image has a <code>ComponentColorModel</code> with alpha. The
0N/A * color data in this image is considered not to be premultiplied with
0N/A * alpha. The byte data is interleaved in a single
0N/A * byte array in the order A, B, G, R
0N/A * from lower to higher byte addresses within each pixel.
0N/A */
0N/A public static final int TYPE_4BYTE_ABGR = 6;
0N/A
0N/A /**
0N/A * Represents an image with 8-bit RGBA color components with the colors
0N/A * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
0N/A * image has a <code>ComponentColorModel</code> with alpha. The color
0N/A * data in this image is considered to be premultiplied with alpha.
0N/A * The byte data is interleaved in a single byte array in the order
0N/A * A, B, G, R from lower to higher byte addresses within each pixel.
0N/A */
0N/A public static final int TYPE_4BYTE_ABGR_PRE = 7;
0N/A
0N/A /**
0N/A * Represents an image with 5-6-5 RGB color components (5-bits red,
0N/A * 6-bits green, 5-bits blue) with no alpha. This image has
0N/A * a <code>DirectColorModel</code>.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_USHORT_565_RGB = 8;
0N/A
0N/A /**
0N/A * Represents an image with 5-5-5 RGB color components (5-bits red,
0N/A * 5-bits green, 5-bits blue) with no alpha. This image has
0N/A * a <code>DirectColorModel</code>.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_USHORT_555_RGB = 9;
0N/A
0N/A /**
0N/A * Represents a unsigned byte grayscale image, non-indexed. This
0N/A * image has a <code>ComponentColorModel</code> with a CS_GRAY
0N/A * {@link ColorSpace}.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_BYTE_GRAY = 10;
0N/A
0N/A /**
0N/A * Represents an unsigned short grayscale image, non-indexed). This
0N/A * image has a <code>ComponentColorModel</code> with a CS_GRAY
0N/A * <code>ColorSpace</code>.
0N/A * When data with non-opaque alpha is stored
0N/A * in an image of this type,
0N/A * the color data must be adjusted to a non-premultiplied form
0N/A * and the alpha discarded,
0N/A * as described in the
0N/A * {@link java.awt.AlphaComposite} documentation.
0N/A */
0N/A public static final int TYPE_USHORT_GRAY = 11;
0N/A
0N/A /**
0N/A * Represents an opaque byte-packed 1, 2, or 4 bit image. The
0N/A * image has an {@link IndexColorModel} without alpha. When this
0N/A * type is used as the <code>imageType</code> argument to the
0N/A * <code>BufferedImage</code> constructor that takes an
0N/A * <code>imageType</code> argument but no <code>ColorModel</code>
0N/A * argument, a 1-bit image is created with an
0N/A * <code>IndexColorModel</code> with two colors in the default
0N/A * sRGB <code>ColorSpace</code>: {0,&nbsp;0,&nbsp;0} and
0N/A * {255,&nbsp;255,&nbsp;255}.
0N/A *
0N/A * <p> Images with 2 or 4 bits per pixel may be constructed via
0N/A * the <code>BufferedImage</code> constructor that takes a
0N/A * <code>ColorModel</code> argument by supplying a
0N/A * <code>ColorModel</code> with an appropriate map size.
0N/A *
0N/A * <p> Images with 8 bits per pixel should use the image types
0N/A * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code>
0N/A * depending on their <code>ColorModel</code>.
0N/A
0N/A * <p> When color data is stored in an image of this type,
0N/A * the closest color in the colormap is determined
0N/A * by the <code>IndexColorModel</code> and the resulting index is stored.
0N/A * Approximation and loss of alpha or color components
0N/A * can result, depending on the colors in the
0N/A * <code>IndexColorModel</code> colormap.
0N/A */
0N/A public static final int TYPE_BYTE_BINARY = 12;
0N/A
0N/A /**
0N/A * Represents an indexed byte image. When this type is used as the
0N/A * <code>imageType</code> argument to the <code>BufferedImage</code>
0N/A * constructor that takes an <code>imageType</code> argument
0N/A * but no <code>ColorModel</code> argument, an
0N/A * <code>IndexColorModel</code> is created with
0N/A * a 256-color 6/6/6 color cube palette with the rest of the colors
0N/A * from 216-255 populated by grayscale values in the
0N/A * default sRGB ColorSpace.
0N/A *
0N/A * <p> When color data is stored in an image of this type,
0N/A * the closest color in the colormap is determined
0N/A * by the <code>IndexColorModel</code> and the resulting index is stored.
0N/A * Approximation and loss of alpha or color components
0N/A * can result, depending on the colors in the
0N/A * <code>IndexColorModel</code> colormap.
0N/A */
0N/A public static final int TYPE_BYTE_INDEXED = 13;
0N/A
0N/A private static final int DCM_RED_MASK = 0x00ff0000;
0N/A private static final int DCM_GREEN_MASK = 0x0000ff00;
0N/A private static final int DCM_BLUE_MASK = 0x000000ff;
0N/A private static final int DCM_ALPHA_MASK = 0xff000000;
0N/A private static final int DCM_565_RED_MASK = 0xf800;
0N/A private static final int DCM_565_GRN_MASK = 0x07E0;
0N/A private static final int DCM_565_BLU_MASK = 0x001F;
0N/A private static final int DCM_555_RED_MASK = 0x7C00;
0N/A private static final int DCM_555_GRN_MASK = 0x03E0;
0N/A private static final int DCM_555_BLU_MASK = 0x001F;
0N/A private static final int DCM_BGR_RED_MASK = 0x0000ff;
0N/A private static final int DCM_BGR_GRN_MASK = 0x00ff00;
0N/A private static final int DCM_BGR_BLU_MASK = 0xff0000;
0N/A
0N/A
0N/A static private native void initIDs();
0N/A static {
0N/A ColorModel.loadLibraries();
0N/A initIDs();
0N/A }
0N/A
0N/A /**
0N/A * Constructs a <code>BufferedImage</code> of one of the predefined
0N/A * image types. The <code>ColorSpace</code> for the image is the
0N/A * default sRGB space.
0N/A * @param width width of the created image
0N/A * @param height height of the created image
0N/A * @param imageType type of the created image
0N/A * @see ColorSpace
0N/A * @see #TYPE_INT_RGB
0N/A * @see #TYPE_INT_ARGB
0N/A * @see #TYPE_INT_ARGB_PRE
0N/A * @see #TYPE_INT_BGR
0N/A * @see #TYPE_3BYTE_BGR
0N/A * @see #TYPE_4BYTE_ABGR
0N/A * @see #TYPE_4BYTE_ABGR_PRE
0N/A * @see #TYPE_BYTE_GRAY
0N/A * @see #TYPE_USHORT_GRAY
0N/A * @see #TYPE_BYTE_BINARY
0N/A * @see #TYPE_BYTE_INDEXED
0N/A * @see #TYPE_USHORT_565_RGB
0N/A * @see #TYPE_USHORT_555_RGB
0N/A */
0N/A public BufferedImage(int width,
0N/A int height,
0N/A int imageType) {
0N/A switch (imageType) {
0N/A case TYPE_INT_RGB:
0N/A {
0N/A colorModel = new DirectColorModel(24,
0N/A 0x00ff0000, // Red
0N/A 0x0000ff00, // Green
0N/A 0x000000ff, // Blue
0N/A 0x0 // Alpha
0N/A );
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_INT_ARGB:
0N/A {
0N/A colorModel = ColorModel.getRGBdefault();
0N/A
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_INT_ARGB_PRE:
0N/A {
0N/A colorModel = new
0N/A DirectColorModel(
0N/A ColorSpace.getInstance(ColorSpace.CS_sRGB),
0N/A 32,
0N/A 0x00ff0000,// Red
0N/A 0x0000ff00,// Green
0N/A 0x000000ff,// Blue
0N/A 0xff000000,// Alpha
0N/A true, // Alpha Premultiplied
0N/A DataBuffer.TYPE_INT
0N/A );
0N/A
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_INT_BGR:
0N/A {
0N/A colorModel = new DirectColorModel(24,
0N/A 0x000000ff, // Red
0N/A 0x0000ff00, // Green
0N/A 0x00ff0000 // Blue
0N/A );
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_3BYTE_BGR:
0N/A {
0N/A ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0N/A int[] nBits = {8, 8, 8};
0N/A int[] bOffs = {2, 1, 0};
0N/A colorModel = new ComponentColorModel(cs, nBits, false, false,
0N/A Transparency.OPAQUE,
0N/A DataBuffer.TYPE_BYTE);
0N/A raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height,
0N/A width*3, 3,
0N/A bOffs, null);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_4BYTE_ABGR:
0N/A {
0N/A ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0N/A int[] nBits = {8, 8, 8, 8};
0N/A int[] bOffs = {3, 2, 1, 0};
0N/A colorModel = new ComponentColorModel(cs, nBits, true, false,
0N/A Transparency.TRANSLUCENT,
0N/A DataBuffer.TYPE_BYTE);
0N/A raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height,
0N/A width*4, 4,
0N/A bOffs, null);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_4BYTE_ABGR_PRE:
0N/A {
0N/A ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0N/A int[] nBits = {8, 8, 8, 8};
0N/A int[] bOffs = {3, 2, 1, 0};
0N/A colorModel = new ComponentColorModel(cs, nBits, true, true,
0N/A Transparency.TRANSLUCENT,
0N/A DataBuffer.TYPE_BYTE);
0N/A raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height,
0N/A width*4, 4,
0N/A bOffs, null);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_BYTE_GRAY:
0N/A {
0N/A ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
0N/A int[] nBits = {8};
0N/A colorModel = new ComponentColorModel(cs, nBits, false, true,
0N/A Transparency.OPAQUE,
0N/A DataBuffer.TYPE_BYTE);
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_USHORT_GRAY:
0N/A {
0N/A ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
0N/A int[] nBits = {16};
0N/A colorModel = new ComponentColorModel(cs, nBits, false, true,
0N/A Transparency.OPAQUE,
0N/A DataBuffer.TYPE_USHORT);
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_BYTE_BINARY:
0N/A {
0N/A byte[] arr = {(byte)0, (byte)0xff};
0N/A
0N/A colorModel = new IndexColorModel(1, 2, arr, arr, arr);
0N/A raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height, 1, 1, null);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_BYTE_INDEXED:
0N/A {
0N/A // Create a 6x6x6 color cube
0N/A int[] cmap = new int[256];
0N/A int i=0;
0N/A for (int r=0; r < 256; r += 51) {
0N/A for (int g=0; g < 256; g += 51) {
0N/A for (int b=0; b < 256; b += 51) {
0N/A cmap[i++] = (r<<16)|(g<<8)|b;
0N/A }
0N/A }
0N/A }
0N/A // And populate the rest of the cmap with gray values
0N/A int grayIncr = 256/(256-i);
0N/A
0N/A // The gray ramp will be between 18 and 252
0N/A int gray = grayIncr*3;
0N/A for (; i < 256; i++) {
0N/A cmap[i] = (gray<<16)|(gray<<8)|gray;
0N/A gray += grayIncr;
0N/A }
0N/A
0N/A colorModel = new IndexColorModel(8, 256, cmap, 0, false, -1,
0N/A DataBuffer.TYPE_BYTE);
0N/A raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height, 1, null);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_USHORT_565_RGB:
0N/A {
0N/A colorModel = new DirectColorModel(16,
0N/A DCM_565_RED_MASK,
0N/A DCM_565_GRN_MASK,
0N/A DCM_565_BLU_MASK
0N/A );
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A case TYPE_USHORT_555_RGB:
0N/A {
0N/A colorModel = new DirectColorModel(15,
0N/A DCM_555_RED_MASK,
0N/A DCM_555_GRN_MASK,
0N/A DCM_555_BLU_MASK
0N/A );
0N/A raster = colorModel.createCompatibleWritableRaster(width,
0N/A height);
0N/A }
0N/A break;
0N/A
0N/A default:
0N/A throw new IllegalArgumentException ("Unknown image type " +
0N/A imageType);
0N/A }
0N/A
0N/A this.imageType = imageType;
0N/A }
0N/A
0N/A /**
0N/A * Constructs a <code>BufferedImage</code> of one of the predefined
0N/A * image types:
0N/A * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED.
0N/A *
0N/A * <p> If the image type is TYPE_BYTE_BINARY, the number of
0N/A * entries in the color model is used to determine whether the
0N/A * image should have 1, 2, or 4 bits per pixel. If the color model
0N/A * has 1 or 2 entries, the image will have 1 bit per pixel. If it
0N/A * has 3 or 4 entries, the image with have 2 bits per pixel. If
0N/A * it has between 5 and 16 entries, the image will have 4 bits per
0N/A * pixel. Otherwise, an IllegalArgumentException will be thrown.
0N/A *
0N/A * @param width width of the created image
0N/A * @param height height of the created image
0N/A * @param imageType type of the created image
0N/A * @param cm <code>IndexColorModel</code> of the created image
0N/A * @throws IllegalArgumentException if the imageType is not
0N/A * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is
0N/A * TYPE_BYTE_BINARY and the color map has more than 16 entries.
0N/A * @see #TYPE_BYTE_BINARY
0N/A * @see #TYPE_BYTE_INDEXED
0N/A */
0N/A public BufferedImage (int width,
0N/A int height,
0N/A int imageType,
0N/A IndexColorModel cm) {
0N/A if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
0N/A throw new IllegalArgumentException("This image types do not have "+
0N/A "premultiplied alpha.");
0N/A }
0N/A
0N/A switch(imageType) {
0N/A case TYPE_BYTE_BINARY:
0N/A int bits; // Will be set below
0N/A int mapSize = cm.getMapSize();
0N/A if (mapSize <= 2) {
0N/A bits = 1;
0N/A } else if (mapSize <= 4) {
0N/A bits = 2;
0N/A } else if (mapSize <= 16) {
0N/A bits = 4;
0N/A } else {
0N/A throw new IllegalArgumentException
0N/A ("Color map for TYPE_BYTE_BINARY " +
0N/A "must have no more than 16 entries");
0N/A }
0N/A raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height, 1, bits, null);
0N/A break;
0N/A
0N/A case TYPE_BYTE_INDEXED:
0N/A raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
0N/A width, height, 1, null);
0N/A break;
0N/A default:
0N/A throw new IllegalArgumentException("Invalid image type (" +
0N/A imageType+"). Image type must"+
0N/A " be either TYPE_BYTE_BINARY or "+
0N/A " TYPE_BYTE_INDEXED");
0N/A }
0N/A
0N/A if (!cm.isCompatibleRaster(raster)) {
0N/A throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
0N/A }
0N/A
0N/A colorModel = cm;
0N/A this.imageType = imageType;
0N/A }
0N/A
0N/A /**
0N/A * Constructs a new <code>BufferedImage</code> with a specified
0N/A * <code>ColorModel</code> and <code>Raster</code>. If the number and
0N/A * types of bands in the <code>SampleModel</code> of the
0N/A * <code>Raster</code> do not match the number and types required by
0N/A * the <code>ColorModel</code> to represent its color and alpha
0N/A * components, a {@link RasterFormatException} is thrown. This
0N/A * method can multiply or divide the color <code>Raster</code> data by
0N/A * alpha to match the <code>alphaPremultiplied</code> state
0N/A * in the <code>ColorModel</code>. Properties for this
0N/A * <code>BufferedImage</code> can be established by passing
0N/A * in a {@link Hashtable} of <code>String</code>/<code>Object</code>
0N/A * pairs.
0N/A * @param cm <code>ColorModel</code> for the new image
0N/A * @param raster <code>Raster</code> for the image data
0N/A * @param isRasterPremultiplied if <code>true</code>, the data in
0N/A * the raster has been premultiplied with alpha.
0N/A * @param properties <code>Hashtable</code> of
0N/A * <code>String</code>/<code>Object</code> pairs.
0N/A * @exception <code>RasterFormatException</code> if the number and
0N/A * types of bands in the <code>SampleModel</code> of the
0N/A * <code>Raster</code> do not match the number and types required by
0N/A * the <code>ColorModel</code> to represent its color and alpha
0N/A * components.
0N/A * @exception <code>IllegalArgumentException</code> if
0N/A * <code>raster</code> is incompatible with <code>cm</code>
0N/A * @see ColorModel
0N/A * @see Raster
0N/A * @see WritableRaster
0N/A */
0N/A
0N/A
0N/A/*
0N/A *
0N/A * FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
0N/A * SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
0N/A *
0N/A */
0N/A public BufferedImage (ColorModel cm,
0N/A WritableRaster raster,
0N/A boolean isRasterPremultiplied,
0N/A Hashtable<?,?> properties) {
0N/A
0N/A if (!cm.isCompatibleRaster(raster)) {
0N/A throw new
0N/A IllegalArgumentException("Raster "+raster+
0N/A " is incompatible with ColorModel "+
0N/A cm);
0N/A }
0N/A
0N/A if ((raster.minX != 0) || (raster.minY != 0)) {
0N/A throw new
0N/A IllegalArgumentException("Raster "+raster+
0N/A " has minX or minY not equal to zero: "
0N/A + raster.minX + " " + raster.minY);
0N/A }
0N/A
0N/A colorModel = cm;
0N/A this.raster = raster;
0N/A this.properties = properties;
0N/A int numBands = raster.getNumBands();
0N/A boolean isAlphaPre = cm.isAlphaPremultiplied();
6395N/A final boolean isStandard = isStandard(cm, raster);
0N/A ColorSpace cs;
0N/A
0N/A // Force the raster data alpha state to match the premultiplied
0N/A // state in the color model
0N/A coerceData(isRasterPremultiplied);
0N/A
0N/A SampleModel sm = raster.getSampleModel();
0N/A cs = cm.getColorSpace();
0N/A int csType = cs.getType();
0N/A if (csType != ColorSpace.TYPE_RGB) {
6395N/A if (csType == ColorSpace.TYPE_GRAY &&
6395N/A isStandard &&
6395N/A cm instanceof ComponentColorModel) {
0N/A // Check if this might be a child raster (fix for bug 4240596)
0N/A if (sm instanceof ComponentSampleModel &&
0N/A ((ComponentSampleModel)sm).getPixelStride() != numBands) {
0N/A imageType = TYPE_CUSTOM;
0N/A } else if (raster instanceof ByteComponentRaster &&
0N/A raster.getNumBands() == 1 &&
0N/A cm.getComponentSize(0) == 8 &&
0N/A ((ByteComponentRaster)raster).getPixelStride() == 1) {
0N/A imageType = TYPE_BYTE_GRAY;
0N/A } else if (raster instanceof ShortComponentRaster &&
0N/A raster.getNumBands() == 1 &&
0N/A cm.getComponentSize(0) == 16 &&
0N/A ((ShortComponentRaster)raster).getPixelStride() == 1) {
0N/A imageType = TYPE_USHORT_GRAY;
0N/A }
0N/A } else {
0N/A imageType = TYPE_CUSTOM;
0N/A }
0N/A return;
0N/A }
0N/A
0N/A if ((raster instanceof IntegerComponentRaster) &&
0N/A (numBands == 3 || numBands == 4)) {
0N/A IntegerComponentRaster iraster =
0N/A (IntegerComponentRaster) raster;
0N/A // Check if the raster params and the color model
0N/A // are correct
0N/A int pixSize = cm.getPixelSize();
0N/A if (iraster.getPixelStride() == 1 &&
6395N/A isStandard &&
6395N/A cm instanceof DirectColorModel &&
0N/A (pixSize == 32 || pixSize == 24))
0N/A {
0N/A // Now check on the DirectColorModel params
0N/A DirectColorModel dcm = (DirectColorModel) cm;
0N/A int rmask = dcm.getRedMask();
0N/A int gmask = dcm.getGreenMask();
0N/A int bmask = dcm.getBlueMask();
0N/A if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK &&
0N/A bmask == DCM_BLUE_MASK)
0N/A {
0N/A if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
0N/A imageType = (isAlphaPre
0N/A ? TYPE_INT_ARGB_PRE
0N/A : TYPE_INT_ARGB);
0N/A }
0N/A else {
0N/A // No Alpha
0N/A if (!dcm.hasAlpha()) {
0N/A imageType = TYPE_INT_RGB;
0N/A }
0N/A }
0N/A } // if (dcm.getRedMask() == DCM_RED_MASK &&
0N/A else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK
0N/A && bmask == DCM_BGR_BLU_MASK) {
0N/A if (!dcm.hasAlpha()) {
0N/A imageType = TYPE_INT_BGR;
0N/A }
0N/A } // if (rmask == DCM_BGR_RED_MASK &&
0N/A } // if (iraster.getPixelStride() == 1
0N/A } // ((raster instanceof IntegerComponentRaster) &&
6395N/A else if ((cm instanceof IndexColorModel) && (numBands == 1) &&
6395N/A isStandard &&
0N/A (!cm.hasAlpha() || !isAlphaPre))
0N/A {
0N/A IndexColorModel icm = (IndexColorModel) cm;
0N/A int pixSize = icm.getPixelSize();
0N/A
6395N/A if (raster instanceof BytePackedRaster) {
0N/A imageType = TYPE_BYTE_BINARY;
0N/A } // if (raster instanceof BytePackedRaster)
6395N/A else if (raster instanceof ByteComponentRaster) {
0N/A ByteComponentRaster braster = (ByteComponentRaster) raster;
0N/A if (braster.getPixelStride() == 1 && pixSize <= 8) {
0N/A imageType = TYPE_BYTE_INDEXED;
0N/A }
0N/A }
0N/A } // else if (cm instanceof IndexColorModel) && (numBands == 1))
0N/A else if ((raster instanceof ShortComponentRaster)
6395N/A && (cm instanceof DirectColorModel)
6395N/A && isStandard
0N/A && (numBands == 3)
0N/A && !cm.hasAlpha())
0N/A {
0N/A DirectColorModel dcm = (DirectColorModel) cm;
0N/A if (dcm.getRedMask() == DCM_565_RED_MASK) {
0N/A if (dcm.getGreenMask() == DCM_565_GRN_MASK &&
0N/A dcm.getBlueMask() == DCM_565_BLU_MASK) {
0N/A imageType = TYPE_USHORT_565_RGB;
0N/A }
0N/A }
0N/A else if (dcm.getRedMask() == DCM_555_RED_MASK) {
0N/A if (dcm.getGreenMask() == DCM_555_GRN_MASK &&
0N/A dcm.getBlueMask() == DCM_555_BLU_MASK) {
0N/A imageType = TYPE_USHORT_555_RGB;
0N/A }
0N/A }
0N/A } // else if ((cm instanceof IndexColorModel) && (numBands == 1))
0N/A else if ((raster instanceof ByteComponentRaster)
0N/A && (cm instanceof ComponentColorModel)
6395N/A && isStandard
0N/A && (raster.getSampleModel() instanceof PixelInterleavedSampleModel)
0N/A && (numBands == 3 || numBands == 4))
0N/A {
0N/A ComponentColorModel ccm = (ComponentColorModel) cm;
0N/A PixelInterleavedSampleModel csm =
0N/A (PixelInterleavedSampleModel)raster.getSampleModel();
0N/A ByteComponentRaster braster = (ByteComponentRaster) raster;
0N/A int[] offs = csm.getBandOffsets();
0N/A if (ccm.getNumComponents() != numBands) {
0N/A throw new RasterFormatException("Number of components in "+
0N/A "ColorModel ("+
0N/A ccm.getNumComponents()+
0N/A ") does not match # in "+
0N/A " Raster ("+numBands+")");
0N/A }
0N/A int[] nBits = ccm.getComponentSize();
0N/A boolean is8bit = true;
0N/A for (int i=0; i < numBands; i++) {
0N/A if (nBits[i] != 8) {
0N/A is8bit = false;
0N/A break;
0N/A }
0N/A }
0N/A if (is8bit &&
6372N/A braster.getPixelStride() == numBands &&
0N/A offs[0] == numBands-1 &&
0N/A offs[1] == numBands-2 &&
6395N/A offs[2] == numBands-3)
0N/A {
6378N/A if (numBands == 3 && !ccm.hasAlpha()) {
0N/A imageType = TYPE_3BYTE_BGR;
0N/A }
6378N/A else if (offs[3] == 0 && ccm.hasAlpha()) {
0N/A imageType = (isAlphaPre
0N/A ? TYPE_4BYTE_ABGR_PRE
0N/A : TYPE_4BYTE_ABGR);
0N/A }
0N/A }
0N/A } // else if ((raster instanceof ByteComponentRaster) &&
0N/A }
0N/A
6395N/A private static boolean isStandard(ColorModel cm, WritableRaster wr) {
6395N/A final Class<? extends ColorModel> cmClass = cm.getClass();
6395N/A final Class<? extends WritableRaster> wrClass = wr.getClass();
6395N/A final Class<? extends SampleModel> smClass = wr.getSampleModel().getClass();
6395N/A
6395N/A final PrivilegedAction<Boolean> checkClassLoadersAction =
6395N/A new PrivilegedAction<Boolean>()
6395N/A {
6395N/A
6395N/A @Override
6395N/A public Boolean run() {
6395N/A final ClassLoader std = System.class.getClassLoader();
6395N/A
6395N/A return (cmClass.getClassLoader() == std) &&
6395N/A (smClass.getClassLoader() == std) &&
6395N/A (wrClass.getClassLoader() == std);
6395N/A }
6395N/A };
6395N/A return AccessController.doPrivileged(checkClassLoadersAction);
6395N/A }
6395N/A
0N/A /**
0N/A * Returns the image type. If it is not one of the known types,
0N/A * TYPE_CUSTOM is returned.
0N/A * @return the image type of this <code>BufferedImage</code>.
0N/A * @see #TYPE_INT_RGB
0N/A * @see #TYPE_INT_ARGB
0N/A * @see #TYPE_INT_ARGB_PRE
0N/A * @see #TYPE_INT_BGR
0N/A * @see #TYPE_3BYTE_BGR
0N/A * @see #TYPE_4BYTE_ABGR
0N/A * @see #TYPE_4BYTE_ABGR_PRE
0N/A * @see #TYPE_BYTE_GRAY
0N/A * @see #TYPE_BYTE_BINARY
0N/A * @see #TYPE_BYTE_INDEXED
0N/A * @see #TYPE_USHORT_GRAY
0N/A * @see #TYPE_USHORT_565_RGB
0N/A * @see #TYPE_USHORT_555_RGB
0N/A * @see #TYPE_CUSTOM
0N/A */
0N/A public int getType() {
0N/A return imageType;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>ColorModel</code>.
0N/A * @return the <code>ColorModel</code> of this
0N/A * <code>BufferedImage</code>.
0N/A */
0N/A public ColorModel getColorModel() {
0N/A return colorModel;
0N/A }
0N/A
0N/A /**
0N/A * Returns the {@link WritableRaster}.
0N/A * @return the <code>WriteableRaster</code> of this
0N/A * <code>BufferedImage</code>.
0N/A */
0N/A public WritableRaster getRaster() {
0N/A return raster;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns a <code>WritableRaster</code> representing the alpha
0N/A * channel for <code>BufferedImage</code> objects
0N/A * with <code>ColorModel</code> objects that support a separate
0N/A * spatial alpha channel, such as <code>ComponentColorModel</code> and
0N/A * <code>DirectColorModel</code>. Returns <code>null</code> if there
0N/A * is no alpha channel associated with the <code>ColorModel</code> in
0N/A * this image. This method assumes that for all
0N/A * <code>ColorModel</code> objects other than
0N/A * <code>IndexColorModel</code>, if the <code>ColorModel</code>
0N/A * supports alpha, there is a separate alpha channel
0N/A * which is stored as the last band of image data.
0N/A * If the image uses an <code>IndexColorModel</code> that
0N/A * has alpha in the lookup table, this method returns
0N/A * <code>null</code> since there is no spatially discrete alpha
0N/A * channel. This method creates a new
0N/A * <code>WritableRaster</code>, but shares the data array.
0N/A * @return a <code>WritableRaster</code> or <code>null</code> if this
0N/A * <code>BufferedImage</code> has no alpha channel associated
0N/A * with its <code>ColorModel</code>.
0N/A */
0N/A public WritableRaster getAlphaRaster() {
0N/A return colorModel.getAlphaRaster(raster);
0N/A }
0N/A
0N/A /**
0N/A * Returns an integer pixel in the default RGB color model
0N/A * (TYPE_INT_ARGB) and default sRGB colorspace. Color
0N/A * conversion takes place if this default model does not match
0N/A * the image <code>ColorModel</code>. There are only 8-bits of
0N/A * precision for each color component in the returned data when using
0N/A * this method.
0N/A *
0N/A * <p>
0N/A *
0N/A * An <code>ArrayOutOfBoundsException</code> may be thrown
0N/A * if the coordinates are not in bounds.
0N/A * However, explicit bounds checking is not guaranteed.
0N/A *
0N/A * @param x the X coordinate of the pixel from which to get
0N/A * the pixel in the default RGB color model and sRGB
0N/A * color space
0N/A * @param y the Y coordinate of the pixel from which to get
0N/A * the pixel in the default RGB color model and sRGB
0N/A * color space
0N/A * @return an integer pixel in the default RGB color model and
0N/A * default sRGB colorspace.
0N/A * @see #setRGB(int, int, int)
0N/A * @see #setRGB(int, int, int, int, int[], int, int)
0N/A */
0N/A public int getRGB(int x, int y) {
0N/A return colorModel.getRGB(raster.getDataElements(x, y, null));
0N/A }
0N/A
0N/A /**
0N/A * Returns an array of integer pixels in the default RGB color model
0N/A * (TYPE_INT_ARGB) and default sRGB color space,
0N/A * from a portion of the image data. Color conversion takes
0N/A * place if the default model does not match the image
0N/A * <code>ColorModel</code>. There are only 8-bits of precision for
0N/A * each color component in the returned data when
0N/A * using this method. With a specified coordinate (x,&nbsp;y) in the
0N/A * image, the ARGB pixel can be accessed in this way:
0N/A * </p>
0N/A *
0N/A * <pre>
0N/A * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre>
0N/A *
0N/A * <p>
0N/A *
0N/A * An <code>ArrayOutOfBoundsException</code> may be thrown
0N/A * if the region is not in bounds.
0N/A * However, explicit bounds checking is not guaranteed.
0N/A *
0N/A * @param startX the starting X coordinate
0N/A * @param startY the starting Y coordinate
0N/A * @param w width of region
0N/A * @param h height of region
0N/A * @param rgbArray if not <code>null</code>, the rgb pixels are
0N/A * written here
0N/A * @param offset offset into the <code>rgbArray</code>
0N/A * @param scansize scanline stride for the <code>rgbArray</code>
0N/A * @return array of RGB pixels.
0N/A * @see #setRGB(int, int, int)
0N/A * @see #setRGB(int, int, int, int, int[], int, int)
0N/A */
0N/A public int[] getRGB(int startX, int startY, int w, int h,
0N/A int[] rgbArray, int offset, int scansize) {
0N/A int yoff = offset;
0N/A int off;
0N/A Object data;
0N/A int nbands = raster.getNumBands();
0N/A int dataType = raster.getDataBuffer().getDataType();
0N/A switch (dataType) {
0N/A case DataBuffer.TYPE_BYTE:
0N/A data = new byte[nbands];
0N/A break;
0N/A case DataBuffer.TYPE_USHORT:
0N/A data = new short[nbands];
0N/A break;
0N/A case DataBuffer.TYPE_INT:
0N/A data = new int[nbands];
0N/A break;
0N/A case DataBuffer.TYPE_FLOAT:
0N/A data = new float[nbands];
0N/A break;
0N/A case DataBuffer.TYPE_DOUBLE:
0N/A data = new double[nbands];
0N/A break;
0N/A default:
0N/A throw new IllegalArgumentException("Unknown data buffer type: "+
0N/A dataType);
0N/A }
0N/A
0N/A if (rgbArray == null) {
0N/A rgbArray = new int[offset+h*scansize];
0N/A }
0N/A
0N/A for (int y = startY; y < startY+h; y++, yoff+=scansize) {
0N/A off = yoff;
0N/A for (int x = startX; x < startX+w; x++) {
0N/A rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x,
0N/A y,
0N/A data));
0N/A }
0N/A }
0N/A
0N/A return rgbArray;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sets a pixel in this <code>BufferedImage</code> to the specified
0N/A * RGB value. The pixel is assumed to be in the default RGB color
0N/A * model, TYPE_INT_ARGB, and default sRGB color space. For images
0N/A * with an <code>IndexColorModel</code>, the index with the nearest
0N/A * color is chosen.
0N/A *
0N/A * <p>
0N/A *
0N/A * An <code>ArrayOutOfBoundsException</code> may be thrown
0N/A * if the coordinates are not in bounds.
0N/A * However, explicit bounds checking is not guaranteed.
0N/A *
0N/A * @param x the X coordinate of the pixel to set
0N/A * @param y the Y coordinate of the pixel to set
0N/A * @param rgb the RGB value
0N/A * @see #getRGB(int, int)
0N/A * @see #getRGB(int, int, int, int, int[], int, int)
0N/A */
0N/A public synchronized void setRGB(int x, int y, int rgb) {
0N/A raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
0N/A }
0N/A
0N/A /**
0N/A * Sets an array of integer pixels in the default RGB color model
0N/A * (TYPE_INT_ARGB) and default sRGB color space,
0N/A * into a portion of the image data. Color conversion takes place
0N/A * if the default model does not match the image
0N/A * <code>ColorModel</code>. There are only 8-bits of precision for
0N/A * each color component in the returned data when
0N/A * using this method. With a specified coordinate (x,&nbsp;y) in the
0N/A * this image, the ARGB pixel can be accessed in this way:
0N/A * <pre>
0N/A * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
0N/A * </pre>
0N/A * WARNING: No dithering takes place.
0N/A *
0N/A * <p>
0N/A *
0N/A * An <code>ArrayOutOfBoundsException</code> may be thrown
0N/A * if the region is not in bounds.
0N/A * However, explicit bounds checking is not guaranteed.
0N/A *
0N/A * @param startX the starting X coordinate
0N/A * @param startY the starting Y coordinate
0N/A * @param w width of the region
0N/A * @param h height of the region
0N/A * @param rgbArray the rgb pixels
0N/A * @param offset offset into the <code>rgbArray</code>
0N/A * @param scansize scanline stride for the <code>rgbArray</code>
0N/A * @see #getRGB(int, int)
0N/A * @see #getRGB(int, int, int, int, int[], int, int)
0N/A */
0N/A public void setRGB(int startX, int startY, int w, int h,
0N/A int[] rgbArray, int offset, int scansize) {
0N/A int yoff = offset;
0N/A int off;
0N/A Object pixel = null;
0N/A
0N/A for (int y = startY; y < startY+h; y++, yoff+=scansize) {
0N/A off = yoff;
0N/A for (int x = startX; x < startX+w; x++) {
0N/A pixel = colorModel.getDataElements(rgbArray[off++], pixel);
0N/A raster.setDataElements(x, y, pixel);
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the width of the <code>BufferedImage</code>.
0N/A * @return the width of this <code>BufferedImage</code>
0N/A */
0N/A public int getWidth() {
0N/A return raster.getWidth();
0N/A }
0N/A
0N/A /**
0N/A * Returns the height of the <code>BufferedImage</code>.
0N/A * @return the height of this <code>BufferedImage</code>
0N/A */
0N/A public int getHeight() {
0N/A return raster.getHeight();
0N/A }
0N/A
0N/A /**
0N/A * Returns the width of the <code>BufferedImage</code>.
0N/A * @param observer ignored
0N/A * @return the width of this <code>BufferedImage</code>
0N/A */
0N/A public int getWidth(ImageObserver observer) {
0N/A return raster.getWidth();
0N/A }
0N/A
0N/A /**
0N/A * Returns the height of the <code>BufferedImage</code>.
0N/A * @param observer ignored
0N/A * @return the height of this <code>BufferedImage</code>
0N/A */
0N/A public int getHeight(ImageObserver observer) {
0N/A return raster.getHeight();
0N/A }
0N/A
0N/A /**
0N/A * Returns the object that produces the pixels for the image.
0N/A * @return the {@link ImageProducer} that is used to produce the
0N/A * pixels for this image.
0N/A * @see ImageProducer
0N/A */
0N/A public ImageProducer getSource() {
0N/A if (osis == null) {
0N/A if (properties == null) {
0N/A properties = new Hashtable();
0N/A }
0N/A osis = new OffScreenImageSource(this, properties);
0N/A }
0N/A return osis;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns a property of the image by name. Individual property names
0N/A * are defined by the various image formats. If a property is not
0N/A * defined for a particular image, this method returns the
0N/A * <code>UndefinedProperty</code> field. If the properties
0N/A * for this image are not yet known, then this method returns
0N/A * <code>null</code> and the <code>ImageObserver</code> object is
0N/A * notified later. The property name "comment" should be used to
0N/A * store an optional comment that can be presented to the user as a
0N/A * description of the image, its source, or its author.
0N/A * @param name the property name
0N/A * @param observer the <code>ImageObserver</code> that receives
0N/A * notification regarding image information
0N/A * @return an {@link Object} that is the property referred to by the
0N/A * specified <code>name</code> or <code>null</code> if the
0N/A * properties of this image are not yet known.
0N/A * @throws <code>NullPointerException</code> if the property name is null.
0N/A * @see ImageObserver
0N/A * @see java.awt.Image#UndefinedProperty
0N/A */
0N/A public Object getProperty(String name, ImageObserver observer) {
0N/A return getProperty(name);
0N/A }
0N/A
0N/A /**
0N/A * Returns a property of the image by name.
0N/A * @param name the property name
0N/A * @return an <code>Object</code> that is the property referred to by
0N/A * the specified <code>name</code>.
0N/A * @throws <code>NullPointerException</code> if the property name is null.
0N/A */
0N/A public Object getProperty(String name) {
0N/A if (name == null) {
0N/A throw new NullPointerException("null property name is not allowed");
0N/A }
0N/A if (properties == null) {
0N/A return java.awt.Image.UndefinedProperty;
0N/A }
0N/A Object o = properties.get(name);
0N/A if (o == null) {
0N/A o = java.awt.Image.UndefinedProperty;
0N/A }
0N/A return o;
0N/A }
0N/A
0N/A /**
0N/A * This method returns a {@link Graphics2D}, but is here
0N/A * for backwards compatibility. {@link #createGraphics() createGraphics} is more
0N/A * convenient, since it is declared to return a
0N/A * <code>Graphics2D</code>.
0N/A * @return a <code>Graphics2D</code>, which can be used to draw into
0N/A * this image.
0N/A */
0N/A public java.awt.Graphics getGraphics() {
0N/A return createGraphics();
0N/A }
0N/A
0N/A /**
0N/A * Creates a <code>Graphics2D</code>, which can be used to draw into
0N/A * this <code>BufferedImage</code>.
0N/A * @return a <code>Graphics2D</code>, used for drawing into this
0N/A * image.
0N/A */
0N/A public Graphics2D createGraphics() {
0N/A GraphicsEnvironment env =
0N/A GraphicsEnvironment.getLocalGraphicsEnvironment();
0N/A return env.createGraphics(this);
0N/A }
0N/A
0N/A /**
0N/A * Returns a subimage defined by a specified rectangular region.
0N/A * The returned <code>BufferedImage</code> shares the same
0N/A * data array as the original image.
0N/A * @param x the X coordinate of the upper-left corner of the
0N/A * specified rectangular region
0N/A * @param y the Y coordinate of the upper-left corner of the
0N/A * specified rectangular region
0N/A * @param w the width of the specified rectangular region
0N/A * @param h the height of the specified rectangular region
0N/A * @return a <code>BufferedImage</code> that is the subimage of this
0N/A * <code>BufferedImage</code>.
0N/A * @exception <code>RasterFormatException</code> if the specified
0N/A * area is not contained within this <code>BufferedImage</code>.
0N/A */
0N/A public BufferedImage getSubimage (int x, int y, int w, int h) {
0N/A return new BufferedImage (colorModel,
0N/A raster.createWritableChild(x, y, w, h,
0N/A 0, 0, null),
0N/A colorModel.isAlphaPremultiplied(),
0N/A properties);
0N/A }
0N/A
0N/A /**
0N/A * Returns whether or not the alpha has been premultiplied. It
0N/A * returns <code>false</code> if there is no alpha.
0N/A * @return <code>true</code> if the alpha has been premultiplied;
0N/A * <code>false</code> otherwise.
0N/A */
0N/A public boolean isAlphaPremultiplied() {
0N/A return colorModel.isAlphaPremultiplied();
0N/A }
0N/A
0N/A /**
0N/A * Forces the data to match the state specified in the
0N/A * <code>isAlphaPremultiplied</code> variable. It may multiply or
0N/A * divide the color raster data by alpha, or do nothing if the data is
0N/A * in the correct state.
0N/A * @param isAlphaPremultiplied <code>true</code> if the alpha has been
0N/A * premultiplied; <code>false</code> otherwise.
0N/A */
0N/A public void coerceData (boolean isAlphaPremultiplied) {
0N/A if (colorModel.hasAlpha() &&
0N/A colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
0N/A // Make the color model do the conversion
0N/A colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>String</code> representation of this
0N/A * <code>BufferedImage</code> object and its values.
0N/A * @return a <code>String</code> representing this
0N/A * <code>BufferedImage</code>.
0N/A */
0N/A public String toString() {
215N/A return "BufferedImage@"+Integer.toHexString(hashCode())
215N/A +": type = "+imageType
215N/A +" "+colorModel+" "+raster;
0N/A }
0N/A
0N/A /**
0N/A * Returns a {@link Vector} of {@link RenderedImage} objects that are
0N/A * the immediate sources, not the sources of these immediate sources,
0N/A * of image data for this <code>BufferedImage</code>. This
0N/A * method returns <code>null</code> if the <code>BufferedImage</code>
0N/A * has no information about its immediate sources. It returns an
0N/A * empty <code>Vector</code> if the <code>BufferedImage</code> has no
0N/A * immediate sources.
0N/A * @return a <code>Vector</code> containing immediate sources of
0N/A * this <code>BufferedImage</code> object's image date, or
0N/A * <code>null</code> if this <code>BufferedImage</code> has
0N/A * no information about its immediate sources, or an empty
0N/A * <code>Vector</code> if this <code>BufferedImage</code>
0N/A * has no immediate sources.
0N/A */
0N/A public Vector<RenderedImage> getSources() {
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns an array of names recognized by
0N/A * {@link #getProperty(String) getProperty(String)}
0N/A * or <code>null</code>, if no property names are recognized.
0N/A * @return a <code>String</code> array containing all of the property
0N/A * names that <code>getProperty(String)</code> recognizes;
0N/A * or <code>null</code> if no property names are recognized.
0N/A */
0N/A public String[] getPropertyNames() {
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns the minimum x coordinate of this
0N/A * <code>BufferedImage</code>. This is always zero.
0N/A * @return the minimum x coordinate of this
0N/A * <code>BufferedImage</code>.
0N/A */
0N/A public int getMinX() {
0N/A return raster.getMinX();
0N/A }
0N/A
0N/A /**
0N/A * Returns the minimum y coordinate of this
0N/A * <code>BufferedImage</code>. This is always zero.
0N/A * @return the minimum y coordinate of this
0N/A * <code>BufferedImage</code>.
0N/A */
0N/A public int getMinY() {
0N/A return raster.getMinY();
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>SampleModel</code> associated with this
0N/A * <code>BufferedImage</code>.
0N/A * @return the <code>SampleModel</code> of this
0N/A * <code>BufferedImage</code>.
0N/A */
0N/A public SampleModel getSampleModel() {
0N/A return raster.getSampleModel();
0N/A }
0N/A
0N/A /**
0N/A * Returns the number of tiles in the x direction.
0N/A * This is always one.
0N/A * @return the number of tiles in the x direction.
0N/A */
0N/A public int getNumXTiles() {
0N/A return 1;
0N/A }
0N/A
0N/A /**
0N/A * Returns the number of tiles in the y direction.
0N/A * This is always one.
0N/A * @return the number of tiles in the y direction.
0N/A */
0N/A public int getNumYTiles() {
0N/A return 1;
0N/A }
0N/A
0N/A /**
0N/A * Returns the minimum tile index in the x direction.
0N/A * This is always zero.
0N/A * @return the minimum tile index in the x direction.
0N/A */
0N/A public int getMinTileX() {
0N/A return 0;
0N/A }
0N/A
0N/A /**
0N/A * Returns the minimum tile index in the y direction.
0N/A * This is always zero.
0N/A * @return the mininum tile index in the y direction.
0N/A */
0N/A public int getMinTileY() {
0N/A return 0;
0N/A }
0N/A
0N/A /**
0N/A * Returns the tile width in pixels.
0N/A * @return the tile width in pixels.
0N/A */
0N/A public int getTileWidth() {
0N/A return raster.getWidth();
0N/A }
0N/A
0N/A /**
0N/A * Returns the tile height in pixels.
0N/A * @return the tile height in pixels.
0N/A */
0N/A public int getTileHeight() {
0N/A return raster.getHeight();
0N/A }
0N/A
0N/A /**
0N/A * Returns the x offset of the tile grid relative to the origin,
0N/A * For example, the x coordinate of the location of tile
0N/A * (0,&nbsp;0). This is always zero.
0N/A * @return the x offset of the tile grid.
0N/A */
0N/A public int getTileGridXOffset() {
0N/A return raster.getSampleModelTranslateX();
0N/A }
0N/A
0N/A /**
0N/A * Returns the y offset of the tile grid relative to the origin,
0N/A * For example, the y coordinate of the location of tile
0N/A * (0,&nbsp;0). This is always zero.
0N/A * @return the y offset of the tile grid.
0N/A */
0N/A public int getTileGridYOffset() {
0N/A return raster.getSampleModelTranslateY();
0N/A }
0N/A
0N/A /**
0N/A * Returns tile (<code>tileX</code>,&nbsp;<code>tileY</code>). Note
0N/A * that <code>tileX</code> and <code>tileY</code> are indices
0N/A * into the tile array, not pixel locations. The <code>Raster</code>
0N/A * that is returned is live, which means that it is updated if the
0N/A * image is changed.
0N/A * @param tileX the x index of the requested tile in the tile array
0N/A * @param tileY the y index of the requested tile in the tile array
0N/A * @return a <code>Raster</code> that is the tile defined by the
0N/A * arguments <code>tileX</code> and <code>tileY</code>.
0N/A * @exception <code>ArrayIndexOutOfBoundsException</code> if both
0N/A * <code>tileX</code> and <code>tileY</code> are not
0N/A * equal to 0
0N/A */
0N/A public Raster getTile(int tileX, int tileY) {
0N/A if (tileX == 0 && tileY == 0) {
0N/A return raster;
0N/A }
0N/A throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
0N/A " one tile with index 0,0");
0N/A }
0N/A
0N/A /**
0N/A * Returns the image as one large tile. The <code>Raster</code>
0N/A * returned is a copy of the image data is not updated if the
0N/A * image is changed.
0N/A * @return a <code>Raster</code> that is a copy of the image data.
0N/A * @see #setData(Raster)
0N/A */
0N/A public Raster getData() {
0N/A
0N/A // REMIND : this allocates a whole new tile if raster is a
0N/A // subtile. (It only copies in the requested area)
0N/A // We should do something smarter.
0N/A int width = raster.getWidth();
0N/A int height = raster.getHeight();
0N/A int startX = raster.getMinX();
0N/A int startY = raster.getMinY();
0N/A WritableRaster wr =
0N/A Raster.createWritableRaster(raster.getSampleModel(),
0N/A new Point(raster.getSampleModelTranslateX(),
0N/A raster.getSampleModelTranslateY()));
0N/A
0N/A Object tdata = null;
0N/A
0N/A for (int i = startY; i < startY+height; i++) {
0N/A tdata = raster.getDataElements(startX,i,width,1,tdata);
0N/A wr.setDataElements(startX,i,width,1, tdata);
0N/A }
0N/A return wr;
0N/A }
0N/A
0N/A /**
0N/A * Computes and returns an arbitrary region of the
0N/A * <code>BufferedImage</code>. The <code>Raster</code> returned is a
0N/A * copy of the image data and is not updated if the image is
0N/A * changed.
0N/A * @param rect the region of the <code>BufferedImage</code> to be
0N/A * returned.
0N/A * @return a <code>Raster</code> that is a copy of the image data of
0N/A * the specified region of the <code>BufferedImage</code>
0N/A * @see #setData(Raster)
0N/A */
0N/A public Raster getData(Rectangle rect) {
0N/A SampleModel sm = raster.getSampleModel();
0N/A SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
0N/A rect.height);
0N/A WritableRaster wr = Raster.createWritableRaster(nsm,
0N/A rect.getLocation());
0N/A int width = rect.width;
0N/A int height = rect.height;
0N/A int startX = rect.x;
0N/A int startY = rect.y;
0N/A
0N/A Object tdata = null;
0N/A
0N/A for (int i = startY; i < startY+height; i++) {
0N/A tdata = raster.getDataElements(startX,i,width,1,tdata);
0N/A wr.setDataElements(startX,i,width,1, tdata);
0N/A }
0N/A return wr;
0N/A }
0N/A
0N/A /**
0N/A * Computes an arbitrary rectangular region of the
0N/A * <code>BufferedImage</code> and copies it into a specified
0N/A * <code>WritableRaster</code>. The region to be computed is
0N/A * determined from the bounds of the specified
0N/A * <code>WritableRaster</code>. The specified
0N/A * <code>WritableRaster</code> must have a
0N/A * <code>SampleModel</code> that is compatible with this image. If
0N/A * <code>outRaster</code> is <code>null</code>,
0N/A * an appropriate <code>WritableRaster</code> is created.
0N/A * @param outRaster a <code>WritableRaster</code> to hold the returned
0N/A * part of the image, or <code>null</code>
0N/A * @return a reference to the supplied or created
0N/A * <code>WritableRaster</code>.
0N/A */
0N/A public WritableRaster copyData(WritableRaster outRaster) {
0N/A if (outRaster == null) {
0N/A return (WritableRaster) getData();
0N/A }
0N/A int width = outRaster.getWidth();
0N/A int height = outRaster.getHeight();
0N/A int startX = outRaster.getMinX();
0N/A int startY = outRaster.getMinY();
0N/A
0N/A Object tdata = null;
0N/A
0N/A for (int i = startY; i < startY+height; i++) {
0N/A tdata = raster.getDataElements(startX,i,width,1,tdata);
0N/A outRaster.setDataElements(startX,i,width,1, tdata);
0N/A }
0N/A
0N/A return outRaster;
0N/A }
0N/A
0N/A /**
0N/A * Sets a rectangular region of the image to the contents of the
0N/A * specified <code>Raster</code> <code>r</code>, which is
0N/A * assumed to be in the same coordinate space as the
0N/A * <code>BufferedImage</code>. The operation is clipped to the bounds
0N/A * of the <code>BufferedImage</code>.
0N/A * @param r the specified <code>Raster</code>
0N/A * @see #getData
0N/A * @see #getData(Rectangle)
0N/A */
0N/A public void setData(Raster r) {
0N/A int width = r.getWidth();
0N/A int height = r.getHeight();
0N/A int startX = r.getMinX();
0N/A int startY = r.getMinY();
0N/A
0N/A int[] tdata = null;
0N/A
0N/A // Clip to the current Raster
0N/A Rectangle rclip = new Rectangle(startX, startY, width, height);
0N/A Rectangle bclip = new Rectangle(0, 0, raster.width, raster.height);
0N/A Rectangle intersect = rclip.intersection(bclip);
0N/A if (intersect.isEmpty()) {
0N/A return;
0N/A }
0N/A width = intersect.width;
0N/A height = intersect.height;
0N/A startX = intersect.x;
0N/A startY = intersect.y;
0N/A
0N/A // remind use get/setDataElements for speed if Rasters are
0N/A // compatible
0N/A for (int i = startY; i < startY+height; i++) {
0N/A tdata = r.getPixels(startX,i,width,1,tdata);
0N/A raster.setPixels(startX,i,width,1, tdata);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Adds a tile observer. If the observer is already present,
0N/A * it receives multiple notifications.
0N/A * @param to the specified {@link TileObserver}
0N/A */
0N/A public void addTileObserver (TileObserver to) {
0N/A }
0N/A
0N/A /**
0N/A * Removes a tile observer. If the observer was not registered,
0N/A * nothing happens. If the observer was registered for multiple
0N/A * notifications, it is now registered for one fewer notification.
0N/A * @param to the specified <code>TileObserver</code>.
0N/A */
0N/A public void removeTileObserver (TileObserver to) {
0N/A }
0N/A
0N/A /**
0N/A * Returns whether or not a tile is currently checked out for writing.
0N/A * @param tileX the x index of the tile.
0N/A * @param tileY the y index of the tile.
0N/A * @return <code>true</code> if the tile specified by the specified
0N/A * indices is checked out for writing; <code>false</code>
0N/A * otherwise.
0N/A * @exception <code>ArrayIndexOutOfBoundsException</code> if both
0N/A * <code>tileX</code> and <code>tileY</code> are not equal
0N/A * to 0
0N/A */
0N/A public boolean isTileWritable (int tileX, int tileY) {
0N/A if (tileX == 0 && tileY == 0) {
0N/A return true;
0N/A }
0N/A throw new IllegalArgumentException("Only 1 tile in image");
0N/A }
0N/A
0N/A /**
0N/A * Returns an array of {@link Point} objects indicating which tiles
0N/A * are checked out for writing. Returns <code>null</code> if none are
0N/A * checked out.
0N/A * @return a <code>Point</code> array that indicates the tiles that
0N/A * are checked out for writing, or <code>null</code> if no
0N/A * tiles are checked out for writing.
0N/A */
0N/A public Point[] getWritableTileIndices() {
0N/A Point[] p = new Point[1];
0N/A p[0] = new Point(0, 0);
0N/A
0N/A return p;
0N/A }
0N/A
0N/A /**
0N/A * Returns whether or not any tile is checked out for writing.
0N/A * Semantically equivalent to
0N/A * <pre>
0N/A * (getWritableTileIndices() != null).
0N/A * </pre>
0N/A * @return <code>true</code> if any tile is checked out for writing;
0N/A * <code>false</code> otherwise.
0N/A */
0N/A public boolean hasTileWriters () {
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Checks out a tile for writing. All registered
0N/A * <code>TileObservers</code> are notified when a tile goes from having
0N/A * no writers to having one writer.
0N/A * @param tileX the x index of the tile
0N/A * @param tileY the y index of the tile
0N/A * @return a <code>WritableRaster</code> that is the tile, indicated by
0N/A * the specified indices, to be checked out for writing.
0N/A */
0N/A public WritableRaster getWritableTile (int tileX, int tileY) {
0N/A return raster;
0N/A }
0N/A
0N/A /**
0N/A * Relinquishes permission to write to a tile. If the caller
0N/A * continues to write to the tile, the results are undefined.
0N/A * Calls to this method should only appear in matching pairs
0N/A * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}. Any other leads
0N/A * to undefined results. All registered <code>TileObservers</code>
0N/A * are notified when a tile goes from having one writer to having no
0N/A * writers.
0N/A * @param tileX the x index of the tile
0N/A * @param tileY the y index of the tile
0N/A */
0N/A public void releaseWritableTile (int tileX, int tileY) {
0N/A }
0N/A
0N/A /**
0N/A * Returns the transparency. Returns either OPAQUE, BITMASK,
0N/A * or TRANSLUCENT.
0N/A * @return the transparency of this <code>BufferedImage</code>.
0N/A * @see Transparency#OPAQUE
0N/A * @see Transparency#BITMASK
0N/A * @see Transparency#TRANSLUCENT
0N/A * @since 1.5
0N/A */
0N/A public int getTransparency() {
0N/A return colorModel.getTransparency();
0N/A }
0N/A}