/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
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 SampleModel
and ColorModel
) to be specified in a convenient manner. /**
* A class that allows the format of an image (in particular, its
* {@code SampleModel} and {@code ColorModel}) to be
* specified in a convenient manner.
*
*/
public class ImageTypeSpecifier {
The ColorModel
to be used as a prototype. /**
* The {@code ColorModel} to be used as a prototype.
*/
protected ColorModel colorModel;
A SampleModel
to be used as a prototype. /**
* A {@code SampleModel} to be used as a prototype.
*/
protected SampleModel sampleModel;
Cached specifiers for all of the standard BufferedImage
types. /**
* Cached specifiers for all of the standard
* {@code BufferedImage} 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.
/**
* A constructor to be used by inner subclasses only.
*/
private ImageTypeSpecifier() {}
Constructs an ImageTypeSpecifier
directly from a ColorModel
and a SampleModel
. It is the caller's responsibility to supply compatible parameters. Params: - colorModel – a
ColorModel
. - sampleModel – a
SampleModel
.
Throws: - IllegalArgumentException – if either parameter is
null
. - IllegalArgumentException – if
sampleModel
is not compatible with colorModel
.
/**
* Constructs an {@code ImageTypeSpecifier} directly
* from a {@code ColorModel} and a {@code SampleModel}.
* It is the caller's responsibility to supply compatible
* parameters.
*
* @param colorModel a {@code ColorModel}.
* @param sampleModel a {@code SampleModel}.
*
* @exception IllegalArgumentException if either parameter is
* {@code null}.
* @exception IllegalArgumentException if {@code sampleModel}
* is not compatible with {@code colorModel}.
*/
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 ImageTypeSpecifier
from a RenderedImage
. If a BufferedImage
is being used, one of the factory methods createFromRenderedImage
or createFromBufferedImageType
should be used instead in order to get a more accurate result. Params: - image – a
RenderedImage
.
Throws: - IllegalArgumentException – if the argument is
null
.
/**
* Constructs an {@code ImageTypeSpecifier} from a
* {@code RenderedImage}. If a {@code BufferedImage} is
* being used, one of the factory methods
* {@code createFromRenderedImage} or
* {@code createFromBufferedImageType} should be used instead in
* order to get a more accurate result.
*
* @param image a {@code RenderedImage}.
*
* @exception IllegalArgumentException if the argument is
* {@code null}.
*/
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 DirectColorModel
and a packed SampleModel
to store each pixel packed into in a single byte, short, or int. Params: - colorSpace – the desired
ColorSpace
. - redMask – a contiguous mask indicated the position of the
red channel.
- greenMask – a contiguous mask indicated the position of the
green channel.
- blueMask – a contiguous mask indicated the position of the
blue channel.
- alphaMask – a contiguous mask indicated the position of the
alpha channel.
- transferType – the desired
SampleModel
transfer type. - isAlphaPremultiplied –
true
if the color channels will be premultipled by the alpha channel.
Throws: - IllegalArgumentException – if
colorSpace
is null
. - IllegalArgumentException – if
colorSpace
is not of type TYPE_RGB
. - IllegalArgumentException – if no mask has at least 1
bit set.
- IllegalArgumentException – if
transferType
if not one of DataBuffer.TYPE_BYTE
, DataBuffer.TYPE_USHORT
, or DataBuffer.TYPE_INT
.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* Returns a specifier for a packed image format that will use a
* {@code DirectColorModel} and a packed
* {@code SampleModel} to store each pixel packed into in a
* single byte, short, or int.
*
* @param colorSpace the desired {@code ColorSpace}.
* @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} transfer type.
* @param isAlphaPremultiplied {@code true} if the color channels
* will be premultipled by the alpha channel.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code colorSpace}
* is {@code null}.
* @exception IllegalArgumentException if {@code colorSpace}
* is not of type {@code TYPE_RGB}.
* @exception IllegalArgumentException if no mask has at least 1
* bit set.
* @exception IllegalArgumentException if
* {@code transferType} if not one of
* {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_USHORT}, or
* {@code DataBuffer.TYPE_INT}.
*/
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 = 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 ComponentColorModel
and a PixelInterleavedSampleModel
to store each pixel component in a separate byte, short, or int. Params: - colorSpace – the desired
ColorSpace
. - bandOffsets – an array of
int
s indicating the offsets for each band. - dataType – the desired data type, as one of the enumerations from the
DataBuffer
class. - hasAlpha –
true
if an alpha channel is desired. - isAlphaPremultiplied –
true
if the color channels will be premultipled by the alpha channel.
Throws: - IllegalArgumentException – if
colorSpace
is null
. - IllegalArgumentException – if
bandOffsets
is null
. - IllegalArgumentException – if
dataType
is not one of the legal DataBuffer.TYPE_*
constants. - IllegalArgumentException – if
bandOffsets.length
does not equal the number of color space components, plus 1 if hasAlpha
is true
.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* Returns a specifier for an interleaved image format that will
* use a {@code ComponentColorModel} and a
* {@code PixelInterleavedSampleModel} to store each pixel
* component in a separate byte, short, or int.
*
* @param colorSpace the desired {@code ColorSpace}.
* @param bandOffsets an array of {@code int}s indicating the
* offsets for each band.
* @param dataType the desired data type, as one of the enumerations
* from the {@code DataBuffer} class.
* @param hasAlpha {@code true} if an alpha channel is desired.
* @param isAlphaPremultiplied {@code true} if the color channels
* will be premultipled by the alpha channel.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code colorSpace}
* is {@code null}.
* @exception IllegalArgumentException if {@code bandOffsets}
* is {@code null}.
* @exception IllegalArgumentException if {@code dataType} is
* not one of the legal {@code DataBuffer.TYPE_*} constants.
* @exception IllegalArgumentException if
* {@code bandOffsets.length} does not equal the number of
* color space components, plus 1 if {@code hasAlpha} is
* {@code true}.
*/
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 = bankIndices.clone();
this.bandOffsets = 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 ComponentColorModel
and a BandedSampleModel
to store each channel in a separate array. Params: - colorSpace – the desired
ColorSpace
. - bankIndices – an array of
int
s indicating the bank in which each band will be stored. - bandOffsets – an array of
int
s indicating the starting offset of each band within its bank. - dataType – the desired data type, as one of the enumerations from the
DataBuffer
class. - hasAlpha –
true
if an alpha channel is desired. - isAlphaPremultiplied –
true
if the color channels will be premultipled by the alpha channel.
Throws: - IllegalArgumentException – if
colorSpace
is null
. - IllegalArgumentException – if
bankIndices
is null
. - IllegalArgumentException – if
bandOffsets
is null
. - IllegalArgumentException – if the lengths of
bankIndices
and bandOffsets
differ. - IllegalArgumentException – if
bandOffsets.length
does not equal the number of color space components, plus 1 if hasAlpha
is true
. - IllegalArgumentException – if
dataType
is not one of the legal DataBuffer.TYPE_*
constants.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* Returns a specifier for a banded image format that will use a
* {@code ComponentColorModel} and a
* {@code BandedSampleModel} to store each channel in a
* separate array.
*
* @param colorSpace the desired {@code ColorSpace}.
* @param bankIndices an array of {@code int}s indicating the
* bank in which each band will be stored.
* @param bandOffsets an array of {@code int}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} class.
* @param hasAlpha {@code true} if an alpha channel is desired.
* @param isAlphaPremultiplied {@code true} if the color channels
* will be premultipled by the alpha channel.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code colorSpace}
* is {@code null}.
* @exception IllegalArgumentException if {@code bankIndices}
* is {@code null}.
* @exception IllegalArgumentException if {@code bandOffsets}
* is {@code null}.
* @exception IllegalArgumentException if the lengths of
* {@code bankIndices} and {@code bandOffsets} differ.
* @exception IllegalArgumentException if
* {@code bandOffsets.length} does not equal the number of
* color space components, plus 1 if {@code hasAlpha} is
* {@code true}.
* @exception IllegalArgumentException if {@code dataType} is
* not one of the legal {@code DataBuffer.TYPE_*} 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.
Params: - bits – the number of bits per gray value (1, 2, 4, 8, or 16).
- dataType – the desired data type, as one of the enumerations from the
DataBuffer
class. - isSigned –
true
if negative values are to be represented.
Throws: - IllegalArgumentException – if
bits
is not one of 1, 2, 4, 8, or 16. - IllegalArgumentException – if
dataType
is not one of DataBuffer.TYPE_BYTE
, DataBuffer.TYPE_SHORT
, or DataBuffer.TYPE_USHORT
. - IllegalArgumentException – if
bits
is larger than the bit size of the given dataType
.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* 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} class.
* @param isSigned {@code true} if negative values are to
* be represented.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code bits} is
* not one of 1, 2, 4, 8, or 16.
* @exception IllegalArgumentException if {@code dataType} is
* not one of {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_SHORT}, or
* {@code DataBuffer.TYPE_USHORT}.
* @exception IllegalArgumentException if {@code bits} is
* larger than the bit size of the given {@code dataType}.
*/
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.
Params: - bits – the number of bits per gray value (1, 2, 4, 8, or 16).
- dataType – the desired data type, as one of the enumerations from the
DataBuffer
class. - isSigned –
true
if negative values are to be represented. - isAlphaPremultiplied –
true
if the luminance channel will be premultipled by the alpha channel.
Throws: - IllegalArgumentException – if
bits
is not one of 1, 2, 4, 8, or 16. - IllegalArgumentException – if
dataType
is not one of DataBuffer.TYPE_BYTE
, DataBuffer.TYPE_SHORT
, or DataBuffer.TYPE_USHORT
. - IllegalArgumentException – if
bits
is larger than the bit size of the given dataType
.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* 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} class.
* @param isSigned {@code true} if negative values are to
* be represented.
* @param isAlphaPremultiplied {@code true} if the luminance channel
* will be premultipled by the alpha channel.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code bits} is
* not one of 1, 2, 4, 8, or 16.
* @exception IllegalArgumentException if {@code dataType} is
* not one of {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_SHORT}, or
* {@code DataBuffer.TYPE_USHORT}.
* @exception IllegalArgumentException if {@code bits} is
* larger than the bit size of the given {@code dataType}.
*/
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 = redLUT.clone();
this.greenLUT = greenLUT.clone();
this.blueLUT = blueLUT.clone();
if (alphaLUT != null) {
this.alphaLUT = 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.
Params: - redLUT – an array of
byte
s containing the red values for each index. - greenLUT – an array of
byte
s containing * the green values for each index. - blueLUT – an array of
byte
s containing the blue values for each index. - alphaLUT – an array of
byte
s containing the alpha values for each index, or null
to create a fully opaque LUT. - bits – the number of bits in each index.
- dataType – the desired output type, as one of the enumerations from the
DataBuffer
class.
Throws: - IllegalArgumentException – if
redLUT
is null
. - IllegalArgumentException – if
greenLUT
is null
. - IllegalArgumentException – if
blueLUT
is null
. - IllegalArgumentException – if
bits
is not one of 1, 2, 4, 8, or 16. - IllegalArgumentException – if the non-
null
LUT parameters do not have lengths of exactly 1 << bits
. - IllegalArgumentException – if
dataType
is not one of DataBuffer.TYPE_BYTE
, DataBuffer.TYPE_SHORT
, DataBuffer.TYPE_USHORT
, or DataBuffer.TYPE_INT
. - IllegalArgumentException – if
bits
is larger than the bit size of the given dataType
.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* 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}s containing
* the red values for each index.
* @param greenLUT an array of {@code byte}s containing * the
* green values for each index.
* @param blueLUT an array of {@code byte}s containing the
* blue values for each index.
* @param alphaLUT an array of {@code byte}s containing the
* alpha values for each index, or {@code null} 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} class.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code redLUT} is
* {@code null}.
* @exception IllegalArgumentException if {@code greenLUT} is
* {@code null}.
* @exception IllegalArgumentException if {@code blueLUT} is
* {@code null}.
* @exception IllegalArgumentException if {@code bits} is
* not one of 1, 2, 4, 8, or 16.
* @exception IllegalArgumentException if the
* non-{@code null} LUT parameters do not have lengths of
* exactly {@code 1 << bits}.
* @exception IllegalArgumentException if {@code dataType} is
* not one of {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_SHORT},
* {@code DataBuffer.TYPE_USHORT},
* or {@code DataBuffer.TYPE_INT}.
* @exception IllegalArgumentException if {@code bits} is
* larger than the bit size of the given {@code dataType}.
*/
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 ImageTypeSpecifier
that encodes one of the standard BufferedImage
types (other than TYPE_CUSTOM
). Params: - bufferedImageType – an int representing one of the standard
BufferedImage
types.
Throws: - IllegalArgumentException – if
bufferedImageType
is not one of the standard types, or is equal to TYPE_CUSTOM
.
See Also: - BufferedImage
- BufferedImage.TYPE_INT_RGB
- BufferedImage.TYPE_INT_ARGB
- BufferedImage.TYPE_INT_ARGB_PRE
- BufferedImage.TYPE_INT_BGR
- BufferedImage.TYPE_3BYTE_BGR
- BufferedImage.TYPE_4BYTE_ABGR
- BufferedImage.TYPE_4BYTE_ABGR_PRE
- BufferedImage.TYPE_USHORT_565_RGB
- BufferedImage.TYPE_USHORT_555_RGB
- BufferedImage.TYPE_BYTE_GRAY
- BufferedImage.TYPE_USHORT_GRAY
- BufferedImage.TYPE_BYTE_BINARY
- BufferedImage.TYPE_BYTE_INDEXED
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* Returns an {@code ImageTypeSpecifier} that encodes
* one of the standard {@code BufferedImage} types
* (other than {@code TYPE_CUSTOM}).
*
* @param bufferedImageType an int representing one of the standard
* {@code BufferedImage} types.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if
* {@code bufferedImageType} is not one of the standard
* types, or is equal to {@code TYPE_CUSTOM}.
*
* @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 ImageTypeSpecifier
that encodes the layout of a RenderedImage
(which may be a BufferedImage
). Params: - image – a
RenderedImage
.
Throws: - IllegalArgumentException – if
image
is null
.
Returns: an ImageTypeSpecifier
with the desired characteristics.
/**
* Returns an {@code ImageTypeSpecifier} that encodes the
* layout of a {@code RenderedImage} (which may be a
* {@code BufferedImage}).
*
* @param image a {@code RenderedImage}.
*
* @return an {@code ImageTypeSpecifier} with the desired
* characteristics.
*
* @exception IllegalArgumentException if {@code image} is
* {@code null}.
*/
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 BufferedImage
. /**
* Returns an int containing one of the enumerated constant values
* describing image formats from {@code BufferedImage}.
*
* @return an {@code int} representing a
* {@code BufferedImage} 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 ColorModel.getNumComponents
Returns: the number of components in the image.
/**
* Return the number of color components
* specified by this object. This is the same value as returned by
* {@code ColorModel.getNumComponents}
*
* @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 SampleModel.getNumBands
Returns: the number of bands in the image.
/**
* Return the number of bands
* specified by this object. This is the same value as returned by
* {@code SampleModel.getNumBands}
*
* @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.
Params: - band – the index of the band to be queried, as an
int.
Throws: - IllegalArgumentException – if
band
is negative or greater than the largest band index.
Returns: an int specifying a number of bits.
/**
* 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} 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 SampleModel
based on the settings encapsulated within this object. The width and height of the SampleModel
will be set to arbitrary values. Returns: a SampleModel
with arbitrary dimensions.
/**
* Returns a {@code SampleModel} based on the settings
* encapsulated within this object. The width and height of the
* {@code SampleModel} will be set to arbitrary values.
*
* @return a {@code SampleModel} with arbitrary dimensions.
*/
public SampleModel getSampleModel() {
return sampleModel;
}
Returns a SampleModel
based on the settings encapsulated within this object. The width and height of the SampleModel
will be set to the supplied values. Params: - width – the desired width of the returned
SampleModel
. - height – the desired height of the returned
SampleModel
.
Throws: - IllegalArgumentException – if either
width
or height
are negative or zero. - IllegalArgumentException – if the product of
width
and height
is greater than Integer.MAX_VALUE
Returns: a SampleModel
with the given dimensions.
/**
* Returns a {@code SampleModel} based on the settings
* encapsulated within this object. The width and height of the
* {@code SampleModel} will be set to the supplied values.
*
* @param width the desired width of the returned {@code SampleModel}.
* @param height the desired height of the returned
* {@code SampleModel}.
*
* @return a {@code SampleModel} with the given dimensions.
*
* @exception IllegalArgumentException if either {@code width} or
* {@code height} are negative or zero.
* @exception IllegalArgumentException if the product of
* {@code width} and {@code height} is greater than
* {@code Integer.MAX_VALUE}
*/
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 ColorModel
specified by this object. Returns: a ColorModel
.
/**
* Returns the {@code ColorModel} specified by this object.
*
* @return a {@code ColorModel}.
*/
public ColorModel getColorModel() {
return colorModel;
}
Creates a BufferedImage
with a given width and height according to the specification embodied in this object. Params: - width – the desired width of the returned
BufferedImage
. - height – the desired height of the returned
BufferedImage
.
Throws: - IllegalArgumentException – if either
width
or height
are negative or zero. - IllegalArgumentException – if the product of
width
and height
is greater than Integer.MAX_VALUE
, or if the number of array elements needed to store the image is greater than Integer.MAX_VALUE
.
Returns: a new BufferedImage
/**
* Creates a {@code BufferedImage} with a given width and
* height according to the specification embodied in this object.
*
* @param width the desired width of the returned
* {@code BufferedImage}.
* @param height the desired height of the returned
* {@code BufferedImage}.
*
* @return a new {@code BufferedImage}
*
* @exception IllegalArgumentException if either {@code width} or
* {@code height} are negative or zero.
* @exception IllegalArgumentException if the product of
* {@code width} and {@code height} is greater than
* {@code Integer.MAX_VALUE}, or if the number of array
* elements needed to store the image is greater than
* {@code Integer.MAX_VALUE}.
*/
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 true
if the given Object
is an ImageTypeSpecifier
and has a SampleModel
and ColorModel
that are equal to those of this object. Params: - o – the
Object
to be compared for equality.
Returns: true
if the given object is an equivalent ImageTypeSpecifier
.
/**
* Returns {@code true} if the given {@code Object} is
* an {@code ImageTypeSpecifier} and has a
* {@code SampleModel} and {@code ColorModel} that are
* equal to those of this object.
*
* @param o the {@code Object} to be compared for equality.
*
* @return {@code true} if the given object is an equivalent
* {@code ImageTypeSpecifier}.
*/
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.
Returns: a hash code for this ImageTypeSpecifier
/**
* 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!");
}
}
}