BMPImageReaderpublic class BMPImageReader extends ImageReader implements BMPConstantsThis class is the Java Image IO plugin reader for BMP images.
It may subsample the image, clip the image, select sub-bands,
and shift the decoded image origin if the proper decoding parameter
are set in the provided ImageReadParam .
This class supports Microsoft Windows Bitmap Version 3-5,
as well as OS/2 Bitmap Version 2.x (for single-image BMP file). |
Fields Summary |
---|
private static final int | VERSION_2_1_BIT | private static final int | VERSION_2_4_BIT | private static final int | VERSION_2_8_BIT | private static final int | VERSION_2_24_BIT | private static final int | VERSION_3_1_BIT | private static final int | VERSION_3_4_BIT | private static final int | VERSION_3_8_BIT | private static final int | VERSION_3_24_BIT | private static final int | VERSION_3_NT_16_BIT | private static final int | VERSION_3_NT_32_BIT | private static final int | VERSION_4_1_BIT | private static final int | VERSION_4_4_BIT | private static final int | VERSION_4_8_BIT | private static final int | VERSION_4_16_BIT | private static final int | VERSION_4_24_BIT | private static final int | VERSION_4_32_BIT | private static final int | VERSION_3_XP_EMBEDDED | private static final int | VERSION_4_XP_EMBEDDED | private static final int | VERSION_5_XP_EMBEDDED | private long | bitmapFileSize | private long | bitmapOffset | private long | compression | private long | imageSize | private byte[] | palette | private int | imageType | private int | numBands | private boolean | isBottomUp | private int | bitsPerPixel | private int | redMask | private int | greenMask | private int | blueMask | private int | alphaMask | private SampleModel | sampleModel | private SampleModel | originalSampleModel | private ColorModel | colorModel | private ColorModel | originalColorModel | private ImageInputStream | iisThe input stream where reads from | private boolean | gotHeaderIndicates whether the header is read. | private int | widthThe original image width. | private int | heightThe original image height. | private Rectangle | destinationRegionThe destination region. | private Rectangle | sourceRegionThe source region. | private BMPMetadata | metadataThe metadata from the stream. | private BufferedImage | biThe destination image. | private boolean | noTransformIndicates whether subsampled, subregion is required, and offset is
defined | private boolean | seleBandIndicates whether subband is selected. | private int | scaleXThe scaling factors. | private int | scaleY | private int[] | sourceBandssource and destination bands. | private int[] | destBands |
Constructors Summary |
---|
public BMPImageReader(ImageReaderSpi originator)Constructs BMPImageReader from the provided
ImageReaderSpi .
super(originator);
|
Methods Summary |
---|
public boolean | canReadRaster()
return true;
| private void | checkIndex(int imageIndex)
if (imageIndex != 0) {
throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
}
| private void | decodeRLE4(int imSize, int padding, byte[] values, byte[] bdata)
byte[] val = new byte[width];
int count = 0, l = 0;
int value;
boolean flag = false;
int lineNo = isBottomUp ? height - 1 : 0;
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
int finished = 0;
while (count != imSize) {
value = values[count++] & 0xFF;
if (value == 0) {
// Absolute mode
switch(values[count++] & 0xFF) {
case 0:
// End-of-scanline marker
// End-of-scanline marker
if (lineNo >= sourceRegion.y &&
lineNo < sourceRegion.y + sourceRegion.height) {
if (noTransform) {
int pos = lineNo * (width + 1 >> 1);
for(int i = 0, j = 0; i < width >> 1; i++)
bdata[pos++] =
(byte)((val[j++] << 4) | val[j++]);
if ((width & 1) == 1)
bdata[pos] |= val[width - 1] << 4;
processImageUpdate(bi, 0, lineNo,
destinationRegion.width, 1, 1, 1,
new int[]{0});
finished++;
} else if ((lineNo - sourceRegion.y) % scaleY == 0) {
int currentLine = (lineNo - sourceRegion.y) / scaleY +
destinationRegion.y;
int pos = currentLine * lineStride;
pos += destinationRegion.x >> 1;
int shift = (1 - (destinationRegion.x & 1)) << 2;
for (int i = sourceRegion.x;
i < sourceRegion.x + sourceRegion.width;
i += scaleX) {
bdata[pos] |= val[i] << shift;
shift += 4;
if (shift == 4) {
pos++;
}
shift &= 7;
}
processImageUpdate(bi, 0, currentLine,
destinationRegion.width, 1, 1, 1,
new int[]{0});
finished++;
}
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
if (abortRequested()) {
flag = true;
}
break;
case 1:
// End-of-RLE marker
flag = true;
break;
case 2:
// delta or vector marker
int xoff = values[count++] & 0xFF;
int yoff = values[count] & 0xFF;
// Move to the position xoff, yoff down
l += xoff + yoff*width;
break;
default:
int end = values[count-1] & 0xFF;
for (int i=0; i<end; i++) {
val[l++] = (byte)(((i & 1) == 0) ? (values[count] & 0xf0) >> 4
: (values[count++] & 0x0f));
}
// When end is odd, the above for loop does not
// increment count, so do it now.
if ((end & 1) == 1) {
count++;
}
// Whenever end pixels can fit into odd number of bytes,
// an extra padding byte will be present, so skip that.
if ((((int)Math.ceil(end/2)) & 1) ==1 ) {
count++;
}
break;
}
} else {
// Encoded mode
int alternate[] = { (values[count] & 0xf0) >> 4,
values[count] & 0x0f };
for (int i=0; (i < value) && (l < width); i++) {
val[l++] = (byte)alternate[i & 1];
}
count++;
}
// If End-of-RLE data, then exit the while loop
if (flag) {
break;
}
}
| private void | decodeRLE8(int imSize, int padding, byte[] values, byte[] bdata)
byte val[] = new byte[width * height];
int count = 0, l = 0;
int value;
boolean flag = false;
int lineNo = isBottomUp ? height - 1 : 0;
int lineStride =
((ComponentSampleModel)sampleModel).getScanlineStride();
int finished = 0;
while (count != imSize) {
value = values[count++] & 0xff;
if (value == 0) {
switch(values[count++] & 0xff) {
case 0:
// End-of-scanline marker
if (lineNo >= sourceRegion.y &&
lineNo < sourceRegion.y + sourceRegion.height) {
if (noTransform) {
int pos = lineNo * width;
for(int i = 0; i < width; i++)
bdata[pos++] = val[i];
processImageUpdate(bi, 0, lineNo,
destinationRegion.width, 1, 1, 1,
new int[]{0});
finished++;
} else if ((lineNo - sourceRegion.y) % scaleY == 0) {
int currentLine = (lineNo - sourceRegion.y) / scaleY +
destinationRegion.y;
int pos = currentLine * lineStride;
pos += destinationRegion.x;
for (int i = sourceRegion.x;
i < sourceRegion.x + sourceRegion.width;
i += scaleX)
bdata[pos++] = val[i];
processImageUpdate(bi, 0, currentLine,
destinationRegion.width, 1, 1, 1,
new int[]{0});
finished++;
}
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
if (abortRequested()) {
flag = true;
}
break;
case 1:
// End-of-RLE marker
flag = true;
break;
case 2:
// delta or vector marker
int xoff = values[count++] & 0xff;
int yoff = values[count] & 0xff;
// Move to the position xoff, yoff down
l += xoff + yoff*width;
break;
default:
int end = values[count-1] & 0xff;
for (int i=0; i<end; i++) {
val[l++] = (byte)(values[count++] & 0xff);
}
// Whenever end pixels can fit into odd number of bytes,
// an extra padding byte will be present, so skip that.
if ((end & 1) == 1) {
count++;
}
}
} else {
for (int i=0; i<value; i++) {
val[l++] = (byte)(values[count] & 0xff);
}
count++;
}
// If End-of-RLE data, then exit the while loop
if (flag) {
break;
}
}
| public javax.imageio.ImageReadParam | getDefaultReadParam()
return new ImageReadParam();
| public int | getHeight(int imageIndex)
checkIndex(imageIndex);
readHeader();
return height;
| public javax.imageio.metadata.IIOMetadata | getImageMetadata(int imageIndex)
checkIndex(imageIndex);
if (metadata == null) {
readHeader();
}
return metadata;
| public java.util.Iterator | getImageTypes(int imageIndex)
checkIndex(imageIndex);
readHeader();
ArrayList list = new ArrayList(1);
list.add(new ImageTypeSpecifier(originalColorModel,
originalSampleModel));
return list.iterator();
| public int | getNumImages(boolean allowSearch)Overrides the method defined in the superclass.
if (iis == null) {
throw new IllegalStateException(I18N.getString("GetNumImages0"));
}
if (seekForwardOnly && allowSearch) {
throw new IllegalStateException(I18N.getString("GetNumImages1"));
}
return 1;
| public javax.imageio.metadata.IIOMetadata | getStreamMetadata()
return null;
| public int | getWidth(int imageIndex)
checkIndex(imageIndex);
readHeader();
return width;
| public boolean | isRandomAccessEasy(int imageIndex)
checkIndex(imageIndex);
readHeader();
return metadata.compression == BI_RGB;
| public java.awt.image.BufferedImage | read(int imageIndex, javax.imageio.ImageReadParam param)
if (iis == null) {
throw new IllegalStateException(I18N.getString("BMPImageReader5"));
}
checkIndex(imageIndex);
clearAbortRequest();
processImageStarted(imageIndex);
if (param == null)
param = getDefaultReadParam();
//read header
readHeader();
sourceRegion = new Rectangle(0, 0, 0, 0);
destinationRegion = new Rectangle(0, 0, 0, 0);
computeRegions(param, this.width, this.height,
param.getDestination(),
sourceRegion,
destinationRegion);
scaleX = param.getSourceXSubsampling();
scaleY = param.getSourceYSubsampling();
// If the destination band is set used it
sourceBands = param.getSourceBands();
destBands = param.getDestinationBands();
seleBand = (sourceBands != null) && (destBands != null);
noTransform =
destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
seleBand;
if (!seleBand) {
sourceBands = new int[numBands];
destBands = new int[numBands];
for (int i = 0; i < numBands; i++)
destBands[i] = sourceBands[i] = i;
}
// If the destination is provided, then use it. Otherwise, create new one
bi = param.getDestination();
// Get the image data.
WritableRaster raster = null;
if (bi == null) {
if (sampleModel != null && colorModel != null) {
sampleModel =
sampleModel.createCompatibleSampleModel(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height);
if (seleBand)
sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
raster = Raster.createWritableRaster(sampleModel, new Point());
bi = new BufferedImage(colorModel, raster, false, null);
}
} else {
raster = bi.getWritableTile(0, 0);
sampleModel = bi.getSampleModel();
colorModel = bi.getColorModel();
noTransform &= destinationRegion.equals(raster.getBounds());
}
byte bdata[] = null; // buffer for byte data
short sdata[] = null; // buffer for short data
int idata[] = null; // buffer for int data
// the sampleModel can be null in case of embedded image
if (sampleModel != null) {
if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
bdata = (byte[])
((DataBufferByte)raster.getDataBuffer()).getData();
else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
sdata = (short[])
((DataBufferUShort)raster.getDataBuffer()).getData();
else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
idata = (int[])
((DataBufferInt)raster.getDataBuffer()).getData();
}
// There should only be one tile.
switch(imageType) {
case VERSION_2_1_BIT:
// no compression
read1Bit(bdata);
break;
case VERSION_2_4_BIT:
// no compression
read4Bit(bdata);
break;
case VERSION_2_8_BIT:
// no compression
read8Bit(bdata);
break;
case VERSION_2_24_BIT:
// no compression
read24Bit(bdata);
break;
case VERSION_3_1_BIT:
// 1-bit images cannot be compressed.
read1Bit(bdata);
break;
case VERSION_3_4_BIT:
switch((int)compression) {
case BI_RGB:
read4Bit(bdata);
break;
case BI_RLE4:
readRLE4(bdata);
break;
default:
throw new
RuntimeException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_3_8_BIT:
switch((int)compression) {
case BI_RGB:
read8Bit(bdata);
break;
case BI_RLE8:
readRLE8(bdata);
break;
default:
throw new
RuntimeException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_3_24_BIT:
// 24-bit images are not compressed
read24Bit(bdata);
break;
case VERSION_3_NT_16_BIT:
read16Bit(sdata);
break;
case VERSION_3_NT_32_BIT:
read32Bit(idata);
break;
case VERSION_3_XP_EMBEDDED:
case VERSION_4_XP_EMBEDDED:
case VERSION_5_XP_EMBEDDED:
bi = readEmbedded((int)compression, bi, param);
break;
case VERSION_4_1_BIT:
read1Bit(bdata);
break;
case VERSION_4_4_BIT:
switch((int)compression) {
case BI_RGB:
read4Bit(bdata);
break;
case BI_RLE4:
readRLE4(bdata);
break;
default:
throw new
RuntimeException(I18N.getString("BMPImageReader1"));
}
case VERSION_4_8_BIT:
switch((int)compression) {
case BI_RGB:
read8Bit(bdata);
break;
case BI_RLE8:
readRLE8(bdata);
break;
default:
throw new
RuntimeException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_4_16_BIT:
read16Bit(sdata);
break;
case VERSION_4_24_BIT:
read24Bit(bdata);
break;
case VERSION_4_32_BIT:
read32Bit(idata);
break;
}
if (abortRequested())
processReadAborted();
else
processImageComplete();
return bi;
| private void | read16Bit(short[] sdata)
// Padding bytes at the end of each scanline
// width * bitsPerPixel should be divisible by 32
int padding = width * 2 % 4;
if ( padding != 0)
padding = 4 - padding;
int lineLength = width + padding / 2;
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(sdata, j, width);
iis.skipBytes(padding);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
}
} else {
short[] buf = new short[lineLength];
int lineStride =
((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
} else
iis.skipBytes(lineLength * sourceRegion.y << 1);
int skipLength = lineLength * (scaleY - 1) << 1;
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.readFully(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
//get the bit and assign to the data buffer of the raster
sdata[k + i] = buf[m];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
}
}
| private void | read1Bit(byte[] bdata)
int bytesPerScanline = (width + 7) / 8;
int padding = bytesPerScanline % 4;
if (padding != 0) {
padding = 4 - padding;
}
int lineLength = bytesPerScanline + padding;
if (noTransform) {
int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
// cache the values to avoid duplicated computation
int[] srcOff = new int[destinationRegion.width];
int[] destOff = new int[destinationRegion.width];
int[] srcPos = new int[destinationRegion.width];
int[] destPos = new int[destinationRegion.width];
for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
i < destinationRegion.x + destinationRegion.width;
i++, j++, x += scaleX) {
srcPos[j] = x >> 3;
srcOff[j] = 7 - (x & 7);
destPos[j] = i >> 3;
destOff[j] = 7 - (i & 7);
}
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
bdata[k + destPos[i]] |= v << destOff[i];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
}
}
| private void | read24Bit(byte[] bdata)
// Padding bytes at the end of each scanline
// width * bitsPerPixel should be divisible by 32
int padding = width * 3 % 4;
if ( padding != 0)
padding = 4 - padding;
int lineStride = width * 3;
int lineLength = lineStride + padding;
if (noTransform) {
int j = isBottomUp ? (height -1) * width * 3 : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, lineStride);
iis.skipBytes(padding);
j += isBottomUp ? -lineStride : lineStride;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
}
} else {
byte[] buf = new byte[lineLength];
lineStride =
((ComponentSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x * 3;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0, m = 3 * sourceRegion.x;
i < destinationRegion.width; i++, m += 3 * scaleX) {
//get the bit and assign to the data buffer of the raster
int n = 3 * i + k;
for (int b = 0; b < destBands.length; b++)
bdata[n + destBands[b]] = buf[m + sourceBands[b]];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
}
}
| private void | read32Bit(int[] idata)
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(idata, j, width);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
}
} else {
int[] buf = new int[width];
int lineStride =
((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(width * (height - 1 - lastLine) << 2);
} else
iis.skipBytes(width * sourceRegion.y << 2);
int skipLength = width * (scaleY - 1) << 2;
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.readFully(buf, 0, width);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
//get the bit and assign to the data buffer of the raster
idata[k + i] = buf[m];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
}
}
| private void | read4Bit(byte[] bdata)
int bytesPerScanline = (width + 1) / 2;
// Padding bytes at the end of each scanline
int padding = bytesPerScanline % 4;
if (padding != 0)
padding = 4 - padding;
int lineLength = bytesPerScanline + padding;
if (noTransform) {
int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
// cache the values to avoid duplicated computation
int[] srcOff = new int[destinationRegion.width];
int[] destOff = new int[destinationRegion.width];
int[] srcPos = new int[destinationRegion.width];
int[] destPos = new int[destinationRegion.width];
for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
i < destinationRegion.x + destinationRegion.width;
i++, j++, x += scaleX) {
srcPos[j] = x >> 1;
srcOff[j] = (1 - (x & 1)) << 2;
destPos[j] = i >> 1;
destOff[j] = (1 - (i & 1)) << 2;
}
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
bdata[k + destPos[i]] |= v << destOff[i];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
}
}
| private void | read8Bit(byte[] bdata)
// Padding bytes at the end of each scanline
int padding = width % 4;
if (padding != 0) {
padding = 4 - padding;
}
int lineLength = width + padding;
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, width);
iis.skipBytes(padding);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
((ComponentSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
//get the bit and assign to the data buffer of the raster
bdata[k + i] = buf[m];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
}
}
| private java.awt.image.BufferedImage | readEmbedded(int type, java.awt.image.BufferedImage bi, javax.imageio.ImageReadParam bmpParam)Decodes the jpeg/png image embedded in the bitmap using any jpeg
ImageIO-style plugin.
String format;
switch(type) {
case BI_JPEG:
format = "JPEG";
break;
case BI_PNG:
format = "PNG";
break;
default:
throw new
IOException("Unexpected compression type: " + type);
}
ImageReader reader =
ImageIO.getImageReadersByFormatName(format).next();
if (reader == null) {
throw new RuntimeException(I18N.getString("BMPImageReader4") +
" " + format);
}
// prepare input
byte[] buff = new byte[(int)imageSize];
iis.read(buff);
reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(buff)));
if (bi == null) {
ImageTypeSpecifier embType = reader.getImageTypes(0).next();
bi = embType.createBufferedImage(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height);
}
reader.addIIOReadProgressListener(new EmbeddedProgressAdapter() {
public void imageProgress(ImageReader source,
float percentageDone)
{
processImageProgress(percentageDone);
}
});
reader.addIIOReadUpdateListener(new IIOReadUpdateListener() {
public void imageUpdate(ImageReader source,
BufferedImage theImage,
int minX, int minY,
int width, int height,
int periodX, int periodY,
int[] bands)
{
processImageUpdate(theImage, minX, minY,
width, height,
periodX, periodY, bands);
}
public void passComplete(ImageReader source,
BufferedImage theImage)
{
processPassComplete(theImage);
}
public void passStarted(ImageReader source,
BufferedImage theImage,
int pass,
int minPass, int maxPass,
int minX, int minY,
int periodX, int periodY,
int[] bands)
{
processPassStarted(theImage, pass, minPass, maxPass,
minX, minY, periodX, periodY,
bands);
}
public void thumbnailPassComplete(ImageReader source,
BufferedImage thumb) {}
public void thumbnailPassStarted(ImageReader source,
BufferedImage thumb,
int pass,
int minPass, int maxPass,
int minX, int minY,
int periodX, int periodY,
int[] bands) {}
public void thumbnailUpdate(ImageReader source,
BufferedImage theThumbnail,
int minX, int minY,
int width, int height,
int periodX, int periodY,
int[] bands) {}
});
reader.addIIOReadWarningListener(new IIOReadWarningListener() {
public void warningOccurred(ImageReader source, String warning)
{
processWarningOccurred(warning);
}
});
ImageReadParam param = reader.getDefaultReadParam();
param.setDestination(bi);
param.setDestinationBands(bmpParam.getDestinationBands());
param.setDestinationOffset(bmpParam.getDestinationOffset());
param.setSourceBands(bmpParam.getSourceBands());
param.setSourceRegion(bmpParam.getSourceRegion());
param.setSourceSubsampling(bmpParam.getSourceXSubsampling(),
bmpParam.getSourceYSubsampling(),
bmpParam.getSubsamplingXOffset(),
bmpParam.getSubsamplingYOffset());
reader.read(0, param);
return bi;
| public void | readHeader()
if (gotHeader)
return;
if (iis == null) {
throw new IllegalStateException("Input source not set!");
}
int profileData = 0, profileSize = 0;
this.metadata = new BMPMetadata();
iis.mark();
// read and check the magic marker
byte[] marker = new byte[2];
iis.read(marker);
if (marker[0] != 0x42 || marker[1] != 0x4d)
throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
// Read file size
bitmapFileSize = iis.readUnsignedInt();
// skip the two reserved fields
iis.skipBytes(4);
// Offset to the bitmap from the beginning
bitmapOffset = iis.readUnsignedInt();
// End File Header
// Start BitmapCoreHeader
long size = iis.readUnsignedInt();
if (size == 12) {
width = iis.readShort();
height = iis.readShort();
} else {
width = iis.readInt();
height = iis.readInt();
}
metadata.width = width;
metadata.height = height;
int planes = iis.readUnsignedShort();
bitsPerPixel = iis.readUnsignedShort();
//metadata.colorPlane = planes;
metadata.bitsPerPixel = (short)bitsPerPixel;
// As BMP always has 3 rgb bands, except for Version 5,
// which is bgra
numBands = 3;
if (size == 12) {
// Windows 2.x and OS/2 1.x
metadata.bmpVersion = VERSION_2;
// Classify the image type
if (bitsPerPixel == 1) {
imageType = VERSION_2_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_2_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_2_8_BIT;
} else if (bitsPerPixel == 24) {
imageType = VERSION_2_24_BIT;
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
int sizeOfPalette = numberOfEntries*3;
palette = new byte[sizeOfPalette];
iis.readFully(palette, 0, sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
} else {
compression = iis.readUnsignedInt();
imageSize = iis.readUnsignedInt();
long xPelsPerMeter = iis.readInt();
long yPelsPerMeter = iis.readInt();
long colorsUsed = iis.readUnsignedInt();
long colorsImportant = iis.readUnsignedInt();
metadata.compression = (int)compression;
metadata.xPixelsPerMeter = (int)xPelsPerMeter;
metadata.yPixelsPerMeter = (int)yPelsPerMeter;
metadata.colorsUsed = (int)colorsUsed;
metadata.colorsImportant = (int)colorsImportant;
if (size == 40) {
// Windows 3.x and Windows NT
switch((int)compression) {
case BI_JPEG:
case BI_PNG:
metadata.bmpVersion = VERSION_3;
imageType = VERSION_3_XP_EMBEDDED;
break;
case BI_RGB: // No compression
case BI_RLE8: // 8-bit RLE compression
case BI_RLE4: // 4-bit RLE compression
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries * 4;
palette = new byte[sizeOfPalette];
iis.readFully(palette, 0, sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
if (bitsPerPixel == 1) {
imageType = VERSION_3_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_3_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_3_8_BIT;
} else if (bitsPerPixel == 24) {
imageType = VERSION_3_24_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_3_NT_16_BIT;
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = (1 << 5) - 1;// 0x1F;
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
}
metadata.bmpVersion = VERSION_3;
break;
case BI_BITFIELDS:
if (bitsPerPixel == 16) {
imageType = VERSION_3_NT_16_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
}
// BitsField encoding
redMask = (int)iis.readUnsignedInt();
greenMask = (int)iis.readUnsignedInt();
blueMask = (int)iis.readUnsignedInt();
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
if (colorsUsed != 0) {
// there is a palette
sizeOfPalette = (int)colorsUsed*4;
palette = new byte[sizeOfPalette];
iis.readFully(palette, 0, sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = (int)colorsUsed;
}
metadata.bmpVersion = VERSION_3_NT;
break;
default:
throw new
RuntimeException(I18N.getString("BMPImageReader2"));
}
} else if (size == 108 || size == 124) {
// Windows 4.x BMP
if (size == 108)
metadata.bmpVersion = VERSION_4;
else if (size == 124)
metadata.bmpVersion = VERSION_5;
// rgb masks, valid only if comp is BI_BITFIELDS
redMask = (int)iis.readUnsignedInt();
greenMask = (int)iis.readUnsignedInt();
blueMask = (int)iis.readUnsignedInt();
// Only supported for 32bpp BI_RGB argb
alphaMask = (int)iis.readUnsignedInt();
long csType = iis.readUnsignedInt();
int redX = iis.readInt();
int redY = iis.readInt();
int redZ = iis.readInt();
int greenX = iis.readInt();
int greenY = iis.readInt();
int greenZ = iis.readInt();
int blueX = iis.readInt();
int blueY = iis.readInt();
int blueZ = iis.readInt();
long gammaRed = iis.readUnsignedInt();
long gammaGreen = iis.readUnsignedInt();
long gammaBlue = iis.readUnsignedInt();
if (size == 124) {
metadata.intent = iis.readInt();
profileData = iis.readInt();
profileSize = iis.readInt();
iis.skipBytes(4);
}
metadata.colorSpace = (int)csType;
if (csType == LCS_CALIBRATED_RGB) {
// All the new fields are valid only for this case
metadata.redX = redX;
metadata.redY = redY;
metadata.redZ = redZ;
metadata.greenX = greenX;
metadata.greenY = greenY;
metadata.greenZ = greenZ;
metadata.blueX = blueX;
metadata.blueY = blueY;
metadata.blueZ = blueZ;
metadata.gammaRed = (int)gammaRed;
metadata.gammaGreen = (int)gammaGreen;
metadata.gammaBlue = (int)gammaBlue;
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
palette = new byte[sizeOfPalette];
iis.readFully(palette, 0, sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
switch ((int)compression) {
case BI_JPEG:
case BI_PNG:
if (size == 108) {
imageType = VERSION_4_XP_EMBEDDED;
} else if (size == 124) {
imageType = VERSION_5_XP_EMBEDDED;
}
break;
default:
if (bitsPerPixel == 1) {
imageType = VERSION_4_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_4_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_4_8_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_4_16_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = 0x1F;
}
} else if (bitsPerPixel == 24) {
imageType = VERSION_4_24_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_4_32_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
}
}
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
metadata.alphaMask = alphaMask;
}
} else {
throw new
RuntimeException(I18N.getString("BMPImageReader3"));
}
}
if (height > 0) {
// bottom up image
isBottomUp = true;
} else {
// top down image
isBottomUp = false;
height = Math.abs(height);
}
// Reset Image Layout so there's only one tile.
//Define the color space
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
if (metadata.colorSpace == PROFILE_LINKED ||
metadata.colorSpace == PROFILE_EMBEDDED) {
iis.mark();
iis.skipBytes(profileData - size);
byte[] profile = new byte[profileSize];
iis.readFully(profile, 0, profileSize);
iis.reset();
try {
if (metadata.colorSpace == PROFILE_LINKED)
colorSpace =
new ICC_ColorSpace(ICC_Profile.getInstance(new String(profile)));
else
colorSpace =
new ICC_ColorSpace(ICC_Profile.getInstance(profile));
} catch (Exception e) {
colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
}
}
if (bitsPerPixel == 0 ||
compression == BI_JPEG || compression == BI_PNG )
{
// the colorModel and sampleModel will be initialzed
// by the reader of embedded image
colorModel = null;
sampleModel = null;
} else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
// When number of bitsPerPixel is <= 8, we use IndexColorModel.
numBands = 1;
if (bitsPerPixel == 8) {
int[] bandOffsets = new int[numBands];
for (int i = 0; i < numBands; i++) {
bandOffsets[i] = numBands -1 -i;
}
sampleModel =
new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
width, height,
numBands,
numBands * width,
bandOffsets);
} else {
// 1 and 4 bit pixels can be stored in a packed format.
sampleModel =
new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
width, height,
bitsPerPixel);
}
// Create IndexColorModel from the palette.
byte r[], g[], b[];
if (imageType == VERSION_2_1_BIT ||
imageType == VERSION_2_4_BIT ||
imageType == VERSION_2_8_BIT) {
size = palette.length/3;
if (size > 256) {
size = 256;
}
int off;
r = new byte[(int)size];
g = new byte[(int)size];
b = new byte[(int)size];
for (int i=0; i<(int)size; i++) {
off = 3 * i;
b[i] = palette[off];
g[i] = palette[off+1];
r[i] = palette[off+2];
}
} else {
size = palette.length/4;
if (size > 256) {
size = 256;
}
int off;
r = new byte[(int)size];
g = new byte[(int)size];
b = new byte[(int)size];
for (int i=0; i<size; i++) {
off = 4 * i;
b[i] = palette[off];
g[i] = palette[off+1];
r[i] = palette[off+2];
}
}
if (ImageUtil.isIndicesForGrayscale(r, g, b))
colorModel =
ImageUtil.createColorModel(null, sampleModel);
else
colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
} else if (bitsPerPixel == 16) {
numBands = 3;
sampleModel =
new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
width, height,
new int[] {redMask, greenMask, blueMask});
colorModel =
new DirectColorModel(colorSpace,
16, redMask, greenMask, blueMask, 0,
false, DataBuffer.TYPE_USHORT);
} else if (bitsPerPixel == 32) {
numBands = alphaMask == 0 ? 3 : 4;
// The number of bands in the SampleModel is determined by
// the length of the mask array passed in.
int[] bitMasks = numBands == 3 ?
new int[] {redMask, greenMask, blueMask} :
new int[] {redMask, greenMask, blueMask, alphaMask};
sampleModel =
new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
width, height,
bitMasks);
colorModel =
new DirectColorModel(colorSpace,
32, redMask, greenMask, blueMask, alphaMask,
false, DataBuffer.TYPE_INT);
} else {
numBands = 3;
// Create SampleModel
int[] bandOffsets = new int[numBands];
for (int i = 0; i < numBands; i++) {
bandOffsets[i] = numBands -1 -i;
}
sampleModel =
new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
width, height,
numBands,
numBands * width,
bandOffsets);
colorModel =
ImageUtil.createColorModel(colorSpace, sampleModel);
}
originalSampleModel = sampleModel;
originalColorModel = colorModel;
// Reset to the start of bitmap; then jump to the
//start of image data
iis.reset();
iis.skipBytes(bitmapOffset);
gotHeader = true;
| private void | readRLE4(byte[] bdata)
// If imageSize field is not specified, calculate it.
int imSize = (int)imageSize;
if (imSize == 0) {
imSize = (int)(bitmapFileSize - bitmapOffset);
}
int padding = 0;
// If width is not 32 byte aligned, then while uncompressing each
// scanline will have padding bytes, calculate the amount of padding
int remainder = width % 4;
if (remainder != 0) {
padding = 4 - remainder;
}
// Read till we have the whole image
byte[] values = new byte[imSize];
iis.readFully(values, 0, imSize);
// Decompress the RLE4 compressed data.
decodeRLE4(imSize, padding, values, bdata);
| private void | readRLE8(byte[] bdata)
// If imageSize field is not provided, calculate it.
int imSize = (int)imageSize;
if (imSize == 0) {
imSize = (int)(bitmapFileSize - bitmapOffset);
}
int padding = 0;
// If width is not 32 bit aligned, then while uncompressing each
// scanline will have padding bytes, calculate the amount of padding
int remainder = width % 4;
if (remainder != 0) {
padding = 4 - remainder;
}
// Read till we have the whole image
byte values[] = new byte[imSize];
int bytesRead = 0;
iis.readFully(values, 0, imSize);
// Since data is compressed, decompress it
decodeRLE8(imSize, padding, values, bdata);
| public java.awt.image.Raster | readRaster(int imageIndex, javax.imageio.ImageReadParam param)
BufferedImage bi = read(imageIndex, param);
return bi.getData();
| public void | reset()
super.reset();
iis = null;
resetHeaderInfo();
| private void | resetHeaderInfo()
gotHeader = false;
bi = null;
sampleModel = originalSampleModel = null;
colorModel = originalColorModel = null;
| public void | setInput(java.lang.Object input, boolean seekForwardOnly, boolean ignoreMetadata)Overrides the method defined in the superclass.
super.setInput(input, seekForwardOnly, ignoreMetadata);
iis = (ImageInputStream) input; // Always works
if(iis != null)
iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
resetHeaderInfo();
|
|