- /*
- * @(#)ImageTypeSpecifier.java 1.34 03/12/19
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.imageio;
-
- import java.awt.Point;
- import java.awt.Transparency;
- import java.awt.image.BandedSampleModel;
- import java.awt.image.BufferedImage;
- import java.awt.image.ColorModel;
- import java.awt.color.ColorSpace;
- import java.awt.image.IndexColorModel;
- import java.awt.image.ComponentColorModel;
- import java.awt.image.DataBuffer;
- import java.awt.image.DirectColorModel;
- import java.awt.image.MultiPixelPackedSampleModel;
- import java.awt.image.PixelInterleavedSampleModel;
- import java.awt.image.SinglePixelPackedSampleModel;
- import java.awt.image.Raster;
- import java.awt.image.RenderedImage;
- import java.awt.image.SampleModel;
- import java.awt.image.WritableRaster;
- import java.util.Hashtable;
-
- /**
- * A class that allows the format of an image (in particular, its
- * <code>SampleModel</code> and <code>ColorModel</code>) to be
- * specified in a convenient manner.
- *
- * @version 0.5
- */
- public class ImageTypeSpecifier {
-
- /**
- * The <code>ColorModel</code> to be used as a prototype.
- */
- protected ColorModel colorModel;
-
- /**
- * A <code>SampleModel</code> to be used as a prototype.
- */
- protected SampleModel sampleModel;
-
- /**
- * Cached specifiers for all of the standard
- * <code>BufferedImage</code> types.
- */
- private static ImageTypeSpecifier[] BISpecifier;
-
- // Initialize the standard specifiers
- static {
- ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
-
- BISpecifier =
- new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1];
-
- BISpecifier[BufferedImage.TYPE_CUSTOM] = null;
-
- BISpecifier[BufferedImage.TYPE_INT_RGB] =
- createPacked(sRGB,
- 0x00ff0000,
- 0x0000ff00,
- 0x000000ff,
- 0x0,
- DataBuffer.TYPE_INT,
- false);
-
- BISpecifier[BufferedImage.TYPE_INT_ARGB] =
- createPacked(sRGB,
- 0x00ff0000,
- 0x0000ff00,
- 0x000000ff,
- 0xff000000,
- DataBuffer.TYPE_INT,
- false);
-
- BISpecifier[BufferedImage.TYPE_INT_ARGB_PRE] =
- createPacked(sRGB,
- 0x00ff0000,
- 0x0000ff00,
- 0x000000ff,
- 0xff000000,
- DataBuffer.TYPE_INT,
- true);
-
- BISpecifier[BufferedImage.TYPE_INT_BGR] =
- createPacked(sRGB,
- 0x000000ff,
- 0x0000ff00,
- 0x00ff0000,
- 0x0,
- DataBuffer.TYPE_INT,
- false);
-
- int[] bOffsRGB = { 2, 1, 0 };
- BISpecifier[BufferedImage.TYPE_3BYTE_BGR] =
- createInterleaved(sRGB,
- bOffsRGB,
- DataBuffer.TYPE_BYTE,
- false,
- false);
-
- int[] bOffsABGR = { 3, 2, 1, 0 };
- BISpecifier[BufferedImage.TYPE_4BYTE_ABGR] =
- createInterleaved(sRGB,
- bOffsABGR,
- DataBuffer.TYPE_BYTE,
- true,
- false);
-
- BISpecifier[BufferedImage.TYPE_4BYTE_ABGR_PRE] =
- createInterleaved(sRGB,
- bOffsABGR,
- DataBuffer.TYPE_BYTE,
- true,
- true);
-
- BISpecifier[BufferedImage.TYPE_USHORT_565_RGB] =
- createPacked(sRGB,
- 0xF800,
- 0x07E0,
- 0x001F,
- 0x0,
- DataBuffer.TYPE_USHORT,
- false);
-
- BISpecifier[BufferedImage.TYPE_USHORT_555_RGB] =
- createPacked(sRGB,
- 0x7C00,
- 0x03E0,
- 0x001F,
- 0x0,
- DataBuffer.TYPE_USHORT,
- false);
-
- BISpecifier[BufferedImage.TYPE_BYTE_GRAY] =
- createGrayscale(8,
- DataBuffer.TYPE_BYTE,
- false);
-
- BISpecifier[BufferedImage.TYPE_USHORT_GRAY] =
- createGrayscale(16,
- DataBuffer.TYPE_USHORT,
- false);
-
- BISpecifier[BufferedImage.TYPE_BYTE_BINARY] =
- createGrayscale(1,
- DataBuffer.TYPE_BYTE,
- false);
-
- BufferedImage bi =
- new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED);
- IndexColorModel icm = (IndexColorModel)bi.getColorModel();
- int mapSize = icm.getMapSize();
- byte[] redLUT = new byte[mapSize];
- byte[] greenLUT = new byte[mapSize];
- byte[] blueLUT = new byte[mapSize];
- byte[] alphaLUT = new byte[mapSize];
-
- icm.getReds(redLUT);
- icm.getGreens(greenLUT);
- icm.getBlues(blueLUT);
- icm.getAlphas(alphaLUT);
-
- BISpecifier[BufferedImage.TYPE_BYTE_INDEXED] =
- createIndexed(redLUT, greenLUT, blueLUT, alphaLUT,
- 8,
- DataBuffer.TYPE_BYTE);
- }
-
- /**
- * A constructor to be used by inner subclasses only.
- */
- private ImageTypeSpecifier() {}
-
- /**
- * Constructs an <code>ImageTypeSpecifier</code> directly
- * from a <code>ColorModel</code> and a <code>SampleModel</code>.
- * It is the caller's responsibility to supply compatible
- * parameters.
- *
- * @param colorModel a <code>ColorModel</code>.
- * @param sampleModel a <code>SampleModel</code>.
- *
- * @exception IllegalArgumentException if either parameter is
- * <code>null</code>.
- * @exception IllegalArgumentException if <code>sampleModel</code>
- * is not compatible with <code>colorModel</code>.
- */
- public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
- if (colorModel == null) {
- throw new IllegalArgumentException("colorModel == null!");
- }
- if (sampleModel == null) {
- throw new IllegalArgumentException("sampleModel == null!");
- }
- if (!colorModel.isCompatibleSampleModel(sampleModel)) {
- throw new IllegalArgumentException
- ("sampleModel is incompatible with colorModel!");
- }
- this.colorModel = colorModel;
- this.sampleModel = sampleModel;
- }
-
- /**
- * Constructs an <code>ImageTypeSpecifier</code> from a
- * <code>RenderedImage</code>. If a <code>BufferedImage</code> is
- * being used, one of the factory methods
- * <code>createFromRenderedImage</code> or
- * <code>createFromBufferedImageType</code> should be used instead in
- * order to get a more accurate result.
- *
- * @param image a <code>RenderedImage</code>.
- *
- * @exception IllegalArgumentException if the argument is
- * <code>null</code>.
- */
- public ImageTypeSpecifier(RenderedImage image) {
- if (image == null) {
- throw new IllegalArgumentException("image == null!");
- }
- colorModel = image.getColorModel();
- sampleModel = image.getSampleModel();
- }
-
- // Packed
-
- static class Packed extends ImageTypeSpecifier {
- ColorSpace colorSpace;
- int redMask;
- int greenMask;
- int blueMask;
- int alphaMask;
- int transferType;
- boolean isAlphaPremultiplied;
-
- public Packed(ColorSpace colorSpace,
- int redMask,
- int greenMask,
- int blueMask,
- int alphaMask, // 0 if no alpha
- int transferType,
- boolean isAlphaPremultiplied) {
- if (colorSpace == null) {
- throw new IllegalArgumentException("colorSpace == null!");
- }
- if (colorSpace.getType() != ColorSpace.TYPE_RGB) {
- throw new IllegalArgumentException
- ("colorSpace is not of type TYPE_RGB!");
- }
- if (transferType != DataBuffer.TYPE_BYTE &&
- transferType != DataBuffer.TYPE_USHORT &&
- transferType != DataBuffer.TYPE_INT) {
- throw new IllegalArgumentException
- ("Bad value for transferType!");
- }
- if (redMask == 0 && greenMask == 0 &&
- blueMask == 0 && alphaMask == 0) {
- throw new IllegalArgumentException
- ("No mask has at least 1 bit set!");
- }
- this.colorSpace = colorSpace;
- this.redMask = redMask;
- this.greenMask = greenMask;
- this.blueMask = blueMask;
- this.alphaMask = alphaMask;
- this.transferType = transferType;
- this.isAlphaPremultiplied = isAlphaPremultiplied;
-
- int bits = 32;
- this.colorModel =
- new DirectColorModel(colorSpace,
- bits,
- redMask, greenMask, blueMask,
- alphaMask, isAlphaPremultiplied,
- transferType);
- this.sampleModel = colorModel.createCompatibleSampleModel(1, 1);
- }
- }
-
- /**
- * Returns a specifier for a packed image format that will use a
- * <code>DirectColorModel</code> and a packed
- * <code>SampleModel</code> to store each pixel packed into in a
- * single byte, short, or int.
- *
- * @param colorSpace the desired <code>ColorSpace</code>.
- * @param redMask a contiguous mask indicated the position of the
- * red channel.
- * @param greenMask a contiguous mask indicated the position of the
- * green channel.
- * @param blueMask a contiguous mask indicated the position of the
- * blue channel.
- * @param alphaMask a contiguous mask indicated the position of the
- * alpha channel.
- * @param transferType the desired <code>SampleModel</code> transfer type.
- * @param isAlphaPremultiplied <code>true</code> if the color channels
- * will be premultipled by the alpha channel.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>colorSpace</code>
- * is <code>null</code>.
- * @exception IllegalArgumentException if <code>colorSpace</code>
- * is not of type <code>TYPE_RGB</code>.
- * @exception IllegalArgumentException if no mask has at least 1
- * bit set.
- * @exception IllegalArgumentException if
- * <code>transferType</code> if not one of
- * <code>DataBuffer.TYPE_BYTE</code>,
- * <code>DataBuffer.TYPE_USHORT</code>, or
- * <code>DataBuffer.TYPE_INT</code>.
- */
- public static ImageTypeSpecifier
- createPacked(ColorSpace colorSpace,
- int redMask,
- int greenMask,
- int blueMask,
- int alphaMask, // 0 if no alpha
- int transferType,
- boolean isAlphaPremultiplied) {
- return new ImageTypeSpecifier.Packed(colorSpace,
- redMask,
- greenMask,
- blueMask,
- alphaMask, // 0 if no alpha
- transferType,
- isAlphaPremultiplied);
- }
-
- static ColorModel createComponentCM(ColorSpace colorSpace,
- int numBands,
- int dataType,
- boolean hasAlpha,
- boolean isAlphaPremultiplied) {
- int transparency =
- hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
-
- int[] numBits = new int[numBands];
- int bits = DataBuffer.getDataTypeSize(dataType);
-
- for (int i = 0; i < numBands; i++) {
- numBits[i] = bits;
- }
-
- return new ComponentColorModel(colorSpace,
- numBits,
- hasAlpha,
- isAlphaPremultiplied,
- transparency,
- dataType);
- }
-
- // Interleaved
-
- static class Interleaved extends ImageTypeSpecifier {
- ColorSpace colorSpace;
- int[] bandOffsets;
- int dataType;
- boolean hasAlpha;
- boolean isAlphaPremultiplied;
-
- public Interleaved(ColorSpace colorSpace,
- int[] bandOffsets,
- int dataType,
- boolean hasAlpha,
- boolean isAlphaPremultiplied) {
- if (colorSpace == null) {
- throw new IllegalArgumentException("colorSpace == null!");
- }
- if (bandOffsets == null) {
- throw new IllegalArgumentException("bandOffsets == null!");
- }
- int numBands = colorSpace.getNumComponents() +
- (hasAlpha ? 1 : 0);
- if (bandOffsets.length != numBands) {
- throw new IllegalArgumentException
- ("bandOffsets.length is wrong!");
- }
- if (dataType != DataBuffer.TYPE_BYTE &&
- dataType != DataBuffer.TYPE_SHORT &&
- dataType != DataBuffer.TYPE_USHORT &&
- dataType != DataBuffer.TYPE_INT &&
- dataType != DataBuffer.TYPE_FLOAT &&
- dataType != DataBuffer.TYPE_DOUBLE) {
- throw new IllegalArgumentException
- ("Bad value for dataType!");
- }
- this.colorSpace = colorSpace;
- this.bandOffsets = (int[])bandOffsets.clone();
- this.dataType = dataType;
- this.hasAlpha = hasAlpha;
- this.isAlphaPremultiplied = isAlphaPremultiplied;
-
- this.colorModel =
- ImageTypeSpecifier.createComponentCM(colorSpace,
- bandOffsets.length,
- dataType,
- hasAlpha,
- isAlphaPremultiplied);
-
- int minBandOffset = bandOffsets[0];
- int maxBandOffset = minBandOffset;
- for (int i = 0; i < bandOffsets.length; i++) {
- int offset = bandOffsets[i];
- minBandOffset = Math.min(offset, minBandOffset);
- maxBandOffset = Math.max(offset, maxBandOffset);
- }
- int pixelStride = maxBandOffset - minBandOffset + 1;
-
- int w = 1;
- int h = 1;
- this.sampleModel =
- new PixelInterleavedSampleModel(dataType,
- w, h,
- pixelStride,
- w*pixelStride,
- bandOffsets);
- }
-
- public boolean equals(Object o) {
- if ((o == null) ||
- !(o instanceof ImageTypeSpecifier.Interleaved)) {
- return false;
- }
-
- ImageTypeSpecifier.Interleaved that =
- (ImageTypeSpecifier.Interleaved)o;
-
- if ((!(this.colorSpace.equals(that.colorSpace))) ||
- (this.dataType != that.dataType) ||
- (this.hasAlpha != that.hasAlpha) ||
- (this.isAlphaPremultiplied != that.isAlphaPremultiplied) ||
- (this.bandOffsets.length != that.bandOffsets.length)) {
- return false;
- }
-
- for (int i = 0; i < bandOffsets.length; i++) {
- if (this.bandOffsets[i] != that.bandOffsets[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- public int hashCode() {
- return (super.hashCode() +
- (4 * bandOffsets.length) +
- (25 * dataType) +
- (hasAlpha ? 17 : 18));
- }
- }
-
- /**
- * Returns a specifier for an interleaved image format that will
- * use a <code>ComponentColorModel</code> and a
- * <code>PixelInterleavedSampleModel</code> to store each pixel
- * component in a separate byte, short, or int.
- *
- * @param colorSpace the desired <code>ColorSpace</code>.
- * @param bandOffsets an array of <code>int</code>s indicating the
- * offsets for each band.
- * @param dataType the desired data type, as one of the enumerations
- * from the <code>DataBuffer</code> class.
- * @param hasAlpha <code>true</code> if an alpha channel is desired.
- * @param isAlphaPremultiplied <code>true</code> if the color channels
- * will be premultipled by the alpha channel.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>colorSpace</code>
- * is <code>null</code>.
- * @exception IllegalArgumentException if <code>bandOffsets</code>
- * is <code>null</code>.
- * @exception IllegalArgumentException if <code>dataType</code> is
- * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
- * @exception IllegalArgumentException if
- * <code>bandOffsets.length</code> does not equal the number of
- * color space components, plus 1 if <code>hasAlpha</code> is
- * <code>true</code>.
- */
- public static ImageTypeSpecifier
- createInterleaved(ColorSpace colorSpace,
- int[] bandOffsets,
- int dataType,
- boolean hasAlpha,
- boolean isAlphaPremultiplied) {
- return new ImageTypeSpecifier.Interleaved(colorSpace,
- bandOffsets,
- dataType,
- hasAlpha,
- isAlphaPremultiplied);
- }
-
- // Banded
-
- static class Banded extends ImageTypeSpecifier {
- ColorSpace colorSpace;
- int[] bankIndices;
- int[] bandOffsets;
- int dataType;
- boolean hasAlpha;
- boolean isAlphaPremultiplied;
-
- public Banded(ColorSpace colorSpace,
- int[] bankIndices,
- int[] bandOffsets,
- int dataType,
- boolean hasAlpha,
- boolean isAlphaPremultiplied) {
- if (colorSpace == null) {
- throw new IllegalArgumentException("colorSpace == null!");
- }
- if (bankIndices == null) {
- throw new IllegalArgumentException("bankIndices == null!");
- }
- if (bandOffsets == null) {
- throw new IllegalArgumentException("bandOffsets == null!");
- }
- if (bankIndices.length != bandOffsets.length) {
- throw new IllegalArgumentException
- ("bankIndices.length != bandOffsets.length!");
- }
- if (dataType != DataBuffer.TYPE_BYTE &&
- dataType != DataBuffer.TYPE_SHORT &&
- dataType != DataBuffer.TYPE_USHORT &&
- dataType != DataBuffer.TYPE_INT &&
- dataType != DataBuffer.TYPE_FLOAT &&
- dataType != DataBuffer.TYPE_DOUBLE) {
- throw new IllegalArgumentException
- ("Bad value for dataType!");
- }
- int numBands = colorSpace.getNumComponents() +
- (hasAlpha ? 1 : 0);
- if (bandOffsets.length != numBands) {
- throw new IllegalArgumentException
- ("bandOffsets.length is wrong!");
- }
-
- this.colorSpace = colorSpace;
- this.bankIndices = (int[])bankIndices.clone();
- this.bandOffsets = (int[])bandOffsets.clone();
- this.dataType = dataType;
- this.hasAlpha = hasAlpha;
- this.isAlphaPremultiplied = isAlphaPremultiplied;
-
- this.colorModel =
- ImageTypeSpecifier.createComponentCM(colorSpace,
- bankIndices.length,
- dataType,
- hasAlpha,
- isAlphaPremultiplied);
-
- int w = 1;
- int h = 1;
- this.sampleModel = new BandedSampleModel(dataType,
- w, h,
- w,
- bankIndices,
- bandOffsets);
- }
-
- public boolean equals(Object o) {
- if ((o == null) ||
- !(o instanceof ImageTypeSpecifier.Banded)) {
- return false;
- }
-
- ImageTypeSpecifier.Banded that =
- (ImageTypeSpecifier.Banded)o;
-
- if ((!(this.colorSpace.equals(that.colorSpace))) ||
- (this.dataType != that.dataType) ||
- (this.hasAlpha != that.hasAlpha) ||
- (this.isAlphaPremultiplied != that.isAlphaPremultiplied) ||
- (this.bankIndices.length != that.bankIndices.length) ||
- (this.bandOffsets.length != that.bandOffsets.length)) {
- return false;
- }
-
- for (int i = 0; i < bankIndices.length; i++) {
- if (this.bankIndices[i] != that.bankIndices[i]) {
- return false;
- }
- }
-
- for (int i = 0; i < bandOffsets.length; i++) {
- if (this.bandOffsets[i] != that.bandOffsets[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- public int hashCode() {
- return (super.hashCode() +
- (3 * bandOffsets.length) +
- (7 * bankIndices.length) +
- (21 * dataType) +
- (hasAlpha ? 19 : 29));
- }
- }
-
- /**
- * Returns a specifier for a banded image format that will use a
- * <code>ComponentColorModel</code> and a
- * <code>BandedSampleModel</code> to store each channel in a
- * separate array.
- *
- * @param colorSpace the desired <code>ColorSpace</code>.
- * @param bankIndices an array of <code>int</code>s indicating the
- * bank in which each band will be stored.
- * @param bandOffsets an array of <code>int</code>s indicating the
- * starting offset of each band within its bank.
- * @param dataType the desired data type, as one of the enumerations
- * from the <code>DataBuffer</code> class.
- * @param hasAlpha <code>true</code> if an alpha channel is desired.
- * @param isAlphaPremultiplied <code>true</code> if the color channels
- * will be premultipled by the alpha channel.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>colorSpace</code>
- * is <code>null</code>.
- * @exception IllegalArgumentException if <code>bankIndices</code>
- * is <code>null</code>.
- * @exception IllegalArgumentException if <code>bandOffsets</code>
- * is <code>null</code>.
- * @exception IllegalArgumentException if the lengths of
- * <code>bankIndices</code> and <code>bandOffsets</code> differ.
- * @exception IllegalArgumentException if
- * <code>bandOffsets.length</code> does not equal the number of
- * color space components, plus 1 if <code>hasAlpha</code> is
- * <code>true</code>.
- * @exception IllegalArgumentException if <code>dataType</code> is
- * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
- */
- public static ImageTypeSpecifier
- createBanded(ColorSpace colorSpace,
- int[] bankIndices,
- int[] bandOffsets,
- int dataType,
- boolean hasAlpha,
- boolean isAlphaPremultiplied) {
- return new ImageTypeSpecifier.Banded(colorSpace,
- bankIndices,
- bandOffsets,
- dataType,
- hasAlpha,
- isAlphaPremultiplied);
- }
-
- // Grayscale
-
- static class Grayscale extends ImageTypeSpecifier {
- int bits;
- int dataType;
- boolean isSigned;
- boolean hasAlpha;
- boolean isAlphaPremultiplied;
-
- public Grayscale(int bits,
- int dataType,
- boolean isSigned,
- boolean hasAlpha,
- boolean isAlphaPremultiplied)
- {
- if (bits != 1 && bits != 2 && bits != 4 &&
- bits != 8 && bits != 16)
- {
- throw new IllegalArgumentException("Bad value for bits!");
- }
- if (dataType != DataBuffer.TYPE_BYTE &&
- dataType != DataBuffer.TYPE_SHORT &&
- dataType != DataBuffer.TYPE_USHORT)
- {
- throw new IllegalArgumentException
- ("Bad value for dataType!");
- }
- if (bits > 8 && dataType == DataBuffer.TYPE_BYTE) {
- throw new IllegalArgumentException
- ("Too many bits for dataType!");
- }
-
- this.bits = bits;
- this.dataType = dataType;
- this.isSigned = isSigned;
- this.hasAlpha = hasAlpha;
- this.isAlphaPremultiplied = isAlphaPremultiplied;
-
- ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
-
- if ((bits == 8 && dataType == DataBuffer.TYPE_BYTE) ||
- (bits == 16 &&
- (dataType == DataBuffer.TYPE_SHORT ||
- dataType == DataBuffer.TYPE_USHORT))) {
- // Use component color model & sample model
-
- int numBands = hasAlpha ? 2 : 1;
- int transparency =
- hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
-
-
- int[] nBits = new int[numBands];
- nBits[0] = bits;
- if (numBands == 2) {
- nBits[1] = bits;
- }
- this.colorModel =
- new ComponentColorModel(colorSpace,
- nBits,
- hasAlpha,
- isAlphaPremultiplied,
- transparency,
- dataType);
-
- int[] bandOffsets = new int[numBands];
- bandOffsets[0] = 0;
- if (numBands == 2) {
- bandOffsets[1] = 1;
- }
-
- int w = 1;
- int h = 1;
- this.sampleModel =
- new PixelInterleavedSampleModel(dataType,
- w, h,
- numBands, w*numBands,
- bandOffsets);
- } else {
- int numEntries = 1 << bits;
- byte[] arr = new byte[numEntries];
- for (int i = 0; i < numEntries; i++) {
- arr[i] = (byte)(i*255/(numEntries - 1));
- }
- this.colorModel =
- new IndexColorModel(bits, numEntries, arr, arr, arr);
-
- this.sampleModel =
- new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
- }
- }
- }
-
- /**
- * Returns a specifier for a grayscale image format that will pack
- * pixels of the given bit depth into array elements of
- * the specified data type.
- *
- * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
- * @param dataType the desired data type, as one of the enumerations
- * from the <code>DataBuffer</code> class.
- * @param isSigned <code>true</code> if negative values are to
- * be represented.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>bits</code> is
- * not one of 1, 2, 4, 8, or 16.
- * @exception IllegalArgumentException if <code>dataType</code> is
- * not one of <code>DataBuffer.TYPE_BYTE</code>,
- * <code>DataBuffer.TYPE_SHORT</code>, or
- * <code>DataBuffer.TYPE_USHORT</code>.
- * @exception IllegalArgumentException if <code>bits</code> is
- * larger than the bit size of the given <code>dataType</code>.
- */
- public static ImageTypeSpecifier
- createGrayscale(int bits,
- int dataType,
- boolean isSigned) {
- return new ImageTypeSpecifier.Grayscale(bits,
- dataType,
- isSigned,
- false,
- false);
- }
-
- /**
- * Returns a specifier for a grayscale plus alpha image format
- * that will pack pixels of the given bit depth into array
- * elements of the specified data type.
- *
- * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
- * @param dataType the desired data type, as one of the enumerations
- * from the <code>DataBuffer</code> class.
- * @param isSigned <code>true</code> if negative values are to
- * be represented.
- * @param isAlphaPremultiplied <code>true</code> if the luminance channel
- * will be premultipled by the alpha channel.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>bits</code> is
- * not one of 1, 2, 4, 8, or 16.
- * @exception IllegalArgumentException if <code>dataType</code> is
- * not one of <code>DataBuffer.TYPE_BYTE</code>,
- * <code>DataBuffer.TYPE_SHORT</code>, or
- * <code>DataBuffer.TYPE_USHORT</code>.
- * @exception IllegalArgumentException if <code>bits</code> is
- * larger than the bit size of the given <code>dataType</code>.
- */
- public static ImageTypeSpecifier
- createGrayscale(int bits,
- int dataType,
- boolean isSigned,
- boolean isAlphaPremultiplied) {
- return new ImageTypeSpecifier.Grayscale(bits,
- dataType,
- isSigned,
- true,
- isAlphaPremultiplied);
- }
-
- // Indexed
-
- static class Indexed extends ImageTypeSpecifier {
- byte[] redLUT;
- byte[] greenLUT;
- byte[] blueLUT;
- byte[] alphaLUT = null;
- int bits;
- int dataType;
-
- public Indexed(byte[] redLUT,
- byte[] greenLUT,
- byte[] blueLUT,
- byte[] alphaLUT,
- int bits,
- int dataType) {
- if (redLUT == null || greenLUT == null || blueLUT == null) {
- throw new IllegalArgumentException("LUT is null!");
- }
- if (bits != 1 && bits != 2 && bits != 4 &&
- bits != 8 && bits != 16) {
- throw new IllegalArgumentException("Bad value for bits!");
- }
- if (dataType != DataBuffer.TYPE_BYTE &&
- dataType != DataBuffer.TYPE_SHORT &&
- dataType != DataBuffer.TYPE_USHORT &&
- dataType != DataBuffer.TYPE_INT) {
- throw new IllegalArgumentException
- ("Bad value for dataType!");
- }
- if ((bits > 8 && dataType == DataBuffer.TYPE_BYTE) ||
- (bits > 16 && dataType != DataBuffer.TYPE_INT)) {
- throw new IllegalArgumentException
- ("Too many bits for dataType!");
- }
-
- int len = 1 << bits;
- if (redLUT.length != len ||
- greenLUT.length != len ||
- blueLUT.length != len ||
- (alphaLUT != null && alphaLUT.length != len)) {
- throw new IllegalArgumentException("LUT has improper length!");
- }
- this.redLUT = (byte[])redLUT.clone();
- this.greenLUT = (byte[])greenLUT.clone();
- this.blueLUT = (byte[])blueLUT.clone();
- if (alphaLUT != null) {
- this.alphaLUT = (byte[])alphaLUT.clone();
- }
- this.bits = bits;
- this.dataType = dataType;
-
- if (alphaLUT == null) {
- this.colorModel = new IndexColorModel(bits,
- redLUT.length,
- redLUT,
- greenLUT,
- blueLUT);
- } else {
- this.colorModel = new IndexColorModel(bits,
- redLUT.length,
- redLUT,
- greenLUT,
- blueLUT,
- alphaLUT);
- }
-
- if ((bits == 8 && dataType == DataBuffer.TYPE_BYTE) ||
- (bits == 16 &&
- (dataType == DataBuffer.TYPE_SHORT ||
- dataType == DataBuffer.TYPE_USHORT))) {
- int[] bandOffsets = { 0 };
- this.sampleModel =
- new PixelInterleavedSampleModel(dataType,
- 1, 1, 1, 1,
- bandOffsets);
- } else {
- this.sampleModel =
- new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
- }
- }
- }
-
- /**
- * Returns a specifier for an indexed-color image format that will pack
- * index values of the given bit depth into array elements of
- * the specified data type.
- *
- * @param redLUT an array of <code>byte</code>s containing
- * the red values for each index.
- * @param greenLUT an array of <code>byte</code>s containing * the
- * green values for each index.
- * @param blueLUT an array of <code>byte</code>s containing the
- * blue values for each index.
- * @param alphaLUT an array of <code>byte</code>s containing the
- * alpha values for each index, or <code>null</code> to create a
- * fully opaque LUT.
- * @param bits the number of bits in each index.
- * @param dataType the desired output type, as one of the enumerations
- * from the <code>DataBuffer</code> class.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>redLUT</code> is
- * <code>null</code>.
- * @exception IllegalArgumentException if <code>greenLUT</code> is
- * <code>null</code>.
- * @exception IllegalArgumentException if <code>blueLUT</code> is
- * <code>null</code>.
- * @exception IllegalArgumentException if <code>bits</code> is
- * not one of 1, 2, 4, 8, or 16.
- * @exception IllegalArgumentException if the
- * non-<code>null</code> LUT parameters do not have lengths of
- * exactly <code>1 << bits</code>.
- * @exception IllegalArgumentException if <code>dataType</code> is
- * not one of <code>DataBuffer.TYPE_BYTE</code>,
- * <code>DataBuffer.TYPE_SHORT</code>,
- * <code>DataBuffer.TYPE_USHORT</code>,
- * or <code>DataBuffer.TYPE_INT</code>.
- * @exception IllegalArgumentException if <code>bits</code> is
- * larger than the bit size of the given <code>dataType</code>.
- */
- public static ImageTypeSpecifier
- createIndexed(byte[] redLUT,
- byte[] greenLUT,
- byte[] blueLUT,
- byte[] alphaLUT,
- int bits,
- int dataType) {
- return new ImageTypeSpecifier.Indexed(redLUT,
- greenLUT,
- blueLUT,
- alphaLUT,
- bits,
- dataType);
- }
-
- /**
- * Returns an <code>ImageTypeSpecifier</code> that encodes
- * one of the standard <code>BufferedImage</code> types
- * (other than <code>TYPE_CUSTOM</code>).
- *
- * @param bufferedImageType an int representing one of the standard
- * <code>BufferedImage</code> types.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if
- * <code>bufferedImageType</code> is not one of the standard
- * types, or is equal to <code>TYPE_CUSTOM</code>.
- *
- * @see java.awt.image.BufferedImage
- * @see java.awt.image.BufferedImage#TYPE_INT_RGB
- * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
- * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
- * @see java.awt.image.BufferedImage#TYPE_INT_BGR
- * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
- * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
- * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
- * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
- * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
- * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
- * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
- * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
- * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
- */
- public static
- ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
- if (bufferedImageType >= BufferedImage.TYPE_INT_RGB &&
- bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) {
- return BISpecifier[bufferedImageType];
- } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) {
- throw new IllegalArgumentException("Cannot create from TYPE_CUSTOM!");
- } else {
- throw new IllegalArgumentException("Invalid BufferedImage type!");
- }
- }
-
- /**
- * Returns an <code>ImageTypeSpecifier</code> that encodes the
- * layout of a <code>RenderedImage</code> (which may be a
- * <code>BufferedImage</code>).
- *
- * @param image a <code>RenderedImage</code>.
- *
- * @return an <code>ImageTypeSpecifier</code> with the desired
- * characteristics.
- *
- * @exception IllegalArgumentException if <code>image</code> is
- * <code>null</code>.
- */
- public static
- ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
- if (image == null) {
- throw new IllegalArgumentException("image == null!");
- }
-
- if (image instanceof BufferedImage) {
- int bufferedImageType = ((BufferedImage)image).getType();
- if (bufferedImageType != BufferedImage.TYPE_CUSTOM) {
- return BISpecifier[bufferedImageType];
- }
- }
-
- return new ImageTypeSpecifier(image);
- }
-
- /**
- * Returns an int containing one of the enumerated constant values
- * describing image formats from <code>BufferedImage</code>.
- *
- * @return an <code>int</code> representing a
- * <code>BufferedImage</code> type.
- *
- * @see java.awt.image.BufferedImage
- * @see java.awt.image.BufferedImage#TYPE_CUSTOM
- * @see java.awt.image.BufferedImage#TYPE_INT_RGB
- * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
- * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
- * @see java.awt.image.BufferedImage#TYPE_INT_BGR
- * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
- * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
- * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
- * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
- * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
- * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
- * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
- * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
- * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
- */
- public int getBufferedImageType() {
- BufferedImage bi = createBufferedImage(1, 1);
- return bi.getType();
- }
-
- /**
- * Return the number of color components
- * specified by this object. This is the same value as returned by
- * <code>ColorModel.getNumComponents</code>
- *
- * @return the number of components in the image.
- */
- public int getNumComponents() {
- return colorModel.getNumComponents();
- }
-
- /**
- * Return the number of bands
- * specified by this object. This is the same value as returned by
- * <code>SampleModel.getNumBands</code>
- *
- * @return the number of bands in the image.
- */
- public int getNumBands() {
- return sampleModel.getNumBands();
- }
-
- /**
- * Return the number of bits used to represent samples of the given band.
- *
- * @param band the index of the band to be queried, as an
- * int.
- *
- * @return an int specifying a number of bits.
- *
- * @exception IllegalArgumentException if <code>band</code> is
- * negative or greater than the largest band index.
- */
- public int getBitsPerBand(int band) {
- if (band < 0 | band >= getNumBands()) {
- throw new IllegalArgumentException("band out of range!");
- }
- return sampleModel.getSampleSize(band);
- }
-
- /**
- * Returns a <code>SampleModel</code> based on the settings
- * encapsulated within this object. The width and height of the
- * <code>SampleModel</code> will be set to arbitrary values.
- *
- * @return a <code>SampleModel</code> with arbitrary dimensions.
- */
- public SampleModel getSampleModel() {
- return sampleModel;
- }
-
- /**
- * Returns a <code>SampleModel</code> based on the settings
- * encapsulated within this object. The width and height of the
- * <code>SampleModel</code> will be set to the supplied values.
- *
- * @param width the desired width of the returned <code>SampleModel</code>.
- * @param height the desired height of the returned
- * <code>SampleModel</code>.
- *
- * @return a <code>SampleModel</code> with the given dimensions.
- *
- * @exception IllegalArgumentException if either <code>width</code> or
- * <code>height</code> are negative or zero.
- * @exception IllegalArgumentException if the product of
- * <code>width</code> and <code>height</code> is greater than
- * <code>Integer.MAX_VALUE</code>
- */
- public SampleModel getSampleModel(int width, int height) {
- if ((long)width*height > Integer.MAX_VALUE) {
- throw new IllegalArgumentException
- ("width*height > Integer.MAX_VALUE!");
- }
- return sampleModel.createCompatibleSampleModel(width, height);
- }
-
- /**
- * Returns the <code>ColorModel</code> specified by this object.
- *
- * @return a <code>ColorModel</code>.
- */
- public ColorModel getColorModel() {
- return colorModel;
- }
-
- /**
- * Creates a <code>BufferedImage</code> with a given width and
- * height according to the specification embodied in this object.
- *
- * @param width the desired width of the returned
- * <code>BufferedImage</code>.
- * @param height the desired height of the returned
- * <code>BufferedImage</code>.
- *
- * @return a new <code>BufferedImage</code>
- *
- * @exception IllegalArgumentException if either <code>width</code> or
- * <code>height</code> are negative or zero.
- * @exception IllegalArgumentException if the product of
- * <code>width</code> and <code>height</code> is greater than
- * <code>Integer.MAX_VALUE</code>, or if the number of array
- * elements needed to store the image is greater than
- * <code>Integer.MAX_VALUE</code>.
- */
- public BufferedImage createBufferedImage(int width, int height) {
- try {
- SampleModel sampleModel = getSampleModel(width, height);
- WritableRaster raster =
- Raster.createWritableRaster(sampleModel,
- new Point(0, 0));
- return new BufferedImage(colorModel, raster,
- colorModel.isAlphaPremultiplied(),
- new Hashtable());
- } catch (NegativeArraySizeException e) {
- // Exception most likely thrown from a DataBuffer constructor
- throw new IllegalArgumentException
- ("Array size > Integer.MAX_VALUE!");
- }
- }
-
- /**
- * Returns <code>true</code> if the given <code>Object</code> is
- * an <code>ImageTypeSpecifier</code> and has a
- * <code>SampleModel</code> and <code>ColorModel</code> that are
- * equal to those of this object.
- *
- * @param o the <code>Object</code> to be compared for equality.
- *
- * @return <code>true</code> if the given object is an equivalent
- * <code>ImageTypeSpecifier</code>.
- */
- public boolean equals(Object o) {
- if ((o == null) || !(o instanceof ImageTypeSpecifier)) {
- return false;
- }
-
- ImageTypeSpecifier that = (ImageTypeSpecifier)o;
- return (colorModel.equals(that.colorModel)) &&
- (sampleModel.equals(that.sampleModel));
- }
-
- /**
- * Returns the hash code for this ImageTypeSpecifier.
- *
- * @return a hash code for this ImageTypeSpecifier
- */
- public int hashCode() {
- return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode());
- }
- }