You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1242 lines
47 KiB
1242 lines
47 KiB
/*
|
|
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE 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.
|
|
*
|
|
*/
|
|
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;
|
|
private static ColorSpace sRGB;
|
|
// Initialize the standard specifiers
|
|
static {
|
|
sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
|
|
|
BISpecifier =
|
|
new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1];
|
|
}
|
|
|
|
/**
|
|
* 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}.
|
|
* @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 getSpecifier(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 getSpecifier(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());
|
|
}
|
|
|
|
private static ImageTypeSpecifier getSpecifier(int type) {
|
|
if (BISpecifier[type] == null) {
|
|
BISpecifier[type] = createSpecifier(type);
|
|
}
|
|
return BISpecifier[type];
|
|
}
|
|
|
|
private static ImageTypeSpecifier createSpecifier(int type) {
|
|
switch(type) {
|
|
case BufferedImage.TYPE_INT_RGB:
|
|
return createPacked(sRGB,
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff,
|
|
0x0,
|
|
DataBuffer.TYPE_INT,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_INT_ARGB:
|
|
return createPacked(sRGB,
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff,
|
|
0xff000000,
|
|
DataBuffer.TYPE_INT,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_INT_ARGB_PRE:
|
|
return createPacked(sRGB,
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff,
|
|
0xff000000,
|
|
DataBuffer.TYPE_INT,
|
|
true);
|
|
|
|
case BufferedImage.TYPE_INT_BGR:
|
|
return createPacked(sRGB,
|
|
0x000000ff,
|
|
0x0000ff00,
|
|
0x00ff0000,
|
|
0x0,
|
|
DataBuffer.TYPE_INT,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_3BYTE_BGR:
|
|
return createInterleaved(sRGB,
|
|
new int[] { 2, 1, 0 },
|
|
DataBuffer.TYPE_BYTE,
|
|
false,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_4BYTE_ABGR:
|
|
return createInterleaved(sRGB,
|
|
new int[] { 3, 2, 1, 0 },
|
|
DataBuffer.TYPE_BYTE,
|
|
true,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
|
|
return createInterleaved(sRGB,
|
|
new int[] { 3, 2, 1, 0 },
|
|
DataBuffer.TYPE_BYTE,
|
|
true,
|
|
true);
|
|
|
|
case BufferedImage.TYPE_USHORT_565_RGB:
|
|
return createPacked(sRGB,
|
|
0xF800,
|
|
0x07E0,
|
|
0x001F,
|
|
0x0,
|
|
DataBuffer.TYPE_USHORT,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_USHORT_555_RGB:
|
|
return createPacked(sRGB,
|
|
0x7C00,
|
|
0x03E0,
|
|
0x001F,
|
|
0x0,
|
|
DataBuffer.TYPE_USHORT,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_BYTE_GRAY:
|
|
return createGrayscale(8,
|
|
DataBuffer.TYPE_BYTE,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_USHORT_GRAY:
|
|
return createGrayscale(16,
|
|
DataBuffer.TYPE_USHORT,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_BYTE_BINARY:
|
|
return createGrayscale(1,
|
|
DataBuffer.TYPE_BYTE,
|
|
false);
|
|
|
|
case BufferedImage.TYPE_BYTE_INDEXED:
|
|
{
|
|
|
|
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);
|
|
|
|
return createIndexed(redLUT, greenLUT, blueLUT, alphaLUT,
|
|
8,
|
|
DataBuffer.TYPE_BYTE);
|
|
}
|
|
default:
|
|
throw new IllegalArgumentException("Invalid BufferedImage type!");
|
|
}
|
|
}
|
|
|
|
}
|