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.
1258 lines
33 KiB
1258 lines
33 KiB
5 years ago
|
/*
|
||
|
* Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are met:
|
||
|
*
|
||
|
* -Redistributions of source code must retain the above copyright notice, this
|
||
|
* list of conditions and the following disclaimer.
|
||
|
*
|
||
|
* -Redistribution in binary form must reproduct the above copyright notice,
|
||
|
* this list of conditions and the following disclaimer in the documentation
|
||
|
* and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
|
||
|
* be used to endorse or promote products derived from this software without
|
||
|
* specific prior written permission.
|
||
|
*
|
||
|
* This software is provided "AS IS," without a warranty of any kind. ALL
|
||
|
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
|
||
|
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
|
||
|
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
|
||
|
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
|
||
|
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
|
||
|
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
|
||
|
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
|
||
|
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
|
||
|
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGES.
|
||
|
*
|
||
|
* You acknowledge that Software is not designed,licensed or intended for use in
|
||
|
* the design, construction, operation or maintenance of any nuclear facility.
|
||
|
*/
|
||
|
|
||
|
package com.fr.third.JAI;
|
||
|
import java.awt.Point;
|
||
|
import java.awt.color.ColorSpace;
|
||
|
import java.awt.image.DataBuffer;
|
||
|
import java.awt.image.DataBufferByte;
|
||
|
import java.awt.image.DataBufferInt;
|
||
|
import java.awt.image.DataBufferUShort;
|
||
|
import java.awt.image.DirectColorModel;
|
||
|
import java.awt.image.Raster;
|
||
|
import java.awt.image.RenderedImage;
|
||
|
import java.awt.image.WritableRaster;
|
||
|
import java.awt.image.IndexColorModel;
|
||
|
import java.awt.image.MultiPixelPackedSampleModel;
|
||
|
import java.awt.image.SinglePixelPackedSampleModel;
|
||
|
import java.io.IOException;
|
||
|
import java.io.BufferedInputStream;
|
||
|
import java.io.InputStream;
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
public class BMPImageDecoder extends ImageDecoderImpl {
|
||
|
|
||
|
public BMPImageDecoder(InputStream input, ImageDecodeParam param) {
|
||
|
super(input, param);
|
||
|
}
|
||
|
|
||
|
public RenderedImage decodeAsRenderedImage(int page) throws IOException {
|
||
|
if (page != 0) {
|
||
|
throw new IOException(JaiI18N.getString("BMPImageDecoder8"));
|
||
|
}
|
||
|
return new BMPImage(input);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class BMPImage extends SimpleRenderedImage {
|
||
|
|
||
|
// BMP variables
|
||
|
private BufferedInputStream inputStream;
|
||
|
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, greenMask, blueMask, alphaMask;
|
||
|
|
||
|
// BMP Image types
|
||
|
private static final int VERSION_2_1_BIT = 0;
|
||
|
private static final int VERSION_2_4_BIT = 1;
|
||
|
private static final int VERSION_2_8_BIT = 2;
|
||
|
private static final int VERSION_2_24_BIT = 3;
|
||
|
|
||
|
private static final int VERSION_3_1_BIT = 4;
|
||
|
private static final int VERSION_3_4_BIT = 5;
|
||
|
private static final int VERSION_3_8_BIT = 6;
|
||
|
private static final int VERSION_3_24_BIT = 7;
|
||
|
|
||
|
private static final int VERSION_3_NT_16_BIT = 8;
|
||
|
private static final int VERSION_3_NT_32_BIT = 9;
|
||
|
|
||
|
private static final int VERSION_4_1_BIT = 10;
|
||
|
private static final int VERSION_4_4_BIT = 11;
|
||
|
private static final int VERSION_4_8_BIT = 12;
|
||
|
private static final int VERSION_4_16_BIT = 13;
|
||
|
private static final int VERSION_4_24_BIT = 14;
|
||
|
private static final int VERSION_4_32_BIT = 15;
|
||
|
|
||
|
// Color space types
|
||
|
private static final int LCS_CALIBRATED_RGB = 0;
|
||
|
private static final int LCS_sRGB = 1;
|
||
|
private static final int LCS_CMYK = 2;
|
||
|
|
||
|
// Compression Types
|
||
|
private static final int BI_RGB = 0;
|
||
|
private static final int BI_RLE8 = 1;
|
||
|
private static final int BI_RLE4 = 2;
|
||
|
private static final int BI_BITFIELDS = 3;
|
||
|
|
||
|
private WritableRaster theTile = null;
|
||
|
|
||
|
/**
|
||
|
* Constructor for BMPImage
|
||
|
*
|
||
|
* @param stream
|
||
|
*/
|
||
|
public BMPImage(InputStream stream) {
|
||
|
if (stream instanceof BufferedInputStream) {
|
||
|
inputStream = (BufferedInputStream)stream;
|
||
|
} else {
|
||
|
inputStream = new BufferedInputStream(stream);
|
||
|
}
|
||
|
try {
|
||
|
|
||
|
// Start File Header
|
||
|
if (!(readUnsignedByte(inputStream) == 'B' &&
|
||
|
readUnsignedByte(inputStream) == 'M')) {
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder0"));
|
||
|
}
|
||
|
|
||
|
// Read file size
|
||
|
bitmapFileSize = readDWord(inputStream);
|
||
|
|
||
|
// Read the two reserved fields
|
||
|
readWord(inputStream);
|
||
|
readWord(inputStream);
|
||
|
|
||
|
// Offset to the bitmap from the beginning
|
||
|
bitmapOffset = readDWord(inputStream);
|
||
|
|
||
|
// End File Header
|
||
|
|
||
|
// Start BitmapCoreHeader
|
||
|
long size = readDWord(inputStream);
|
||
|
|
||
|
if (size == 12) {
|
||
|
width = readWord(inputStream);
|
||
|
height = readWord(inputStream);
|
||
|
} else {
|
||
|
width = readLong(inputStream);
|
||
|
height = readLong(inputStream);
|
||
|
}
|
||
|
|
||
|
int planes = readWord(inputStream);
|
||
|
bitsPerPixel = readWord(inputStream);
|
||
|
|
||
|
properties.put("color_planes", new Integer(planes));
|
||
|
properties.put("bits_per_pixel", new Integer(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
|
||
|
properties.put("bmp_version", "BMP v. 2.x");
|
||
|
|
||
|
// 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];
|
||
|
inputStream.read(palette, 0, sizeOfPalette);
|
||
|
properties.put("palette", palette);
|
||
|
} else {
|
||
|
|
||
|
compression = readDWord(inputStream);
|
||
|
imageSize = readDWord(inputStream);
|
||
|
long xPelsPerMeter = readLong(inputStream);
|
||
|
long yPelsPerMeter = readLong(inputStream);
|
||
|
long colorsUsed = readDWord(inputStream);
|
||
|
long colorsImportant = readDWord(inputStream);
|
||
|
|
||
|
switch((int)compression) {
|
||
|
case BI_RGB:
|
||
|
properties.put("compression", "BI_RGB");
|
||
|
break;
|
||
|
|
||
|
case BI_RLE8:
|
||
|
properties.put("compression", "BI_RLE8");
|
||
|
break;
|
||
|
|
||
|
case BI_RLE4:
|
||
|
properties.put("compression", "BI_RLE4");
|
||
|
break;
|
||
|
|
||
|
case BI_BITFIELDS:
|
||
|
properties.put("compression", "BI_BITFIELDS");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
properties.put("x_pixels_per_meter", new Long(xPelsPerMeter));
|
||
|
properties.put("y_pixels_per_meter", new Long(yPelsPerMeter));
|
||
|
properties.put("colors_used", new Long(colorsUsed));
|
||
|
properties.put("colors_important", new Long(colorsImportant));
|
||
|
|
||
|
if (size == 40) {
|
||
|
// Windows 3.x and Windows NT
|
||
|
switch((int)compression) {
|
||
|
|
||
|
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];
|
||
|
inputStream.read(palette, 0, sizeOfPalette);
|
||
|
properties.put("palette", palette);
|
||
|
|
||
|
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 = 0x1F;
|
||
|
properties.put("red_mask", new Integer(redMask));
|
||
|
properties.put("green_mask", new Integer(greenMask));
|
||
|
properties.put("blue_mask", new Integer(blueMask));
|
||
|
} else if (bitsPerPixel == 32) {
|
||
|
imageType = VERSION_3_NT_32_BIT;
|
||
|
redMask = 0x00FF0000;
|
||
|
greenMask = 0x0000FF00;
|
||
|
blueMask = 0x000000FF;
|
||
|
properties.put("red_mask", new Integer(redMask));
|
||
|
properties.put("green_mask", new Integer(greenMask));
|
||
|
properties.put("blue_mask", new Integer(blueMask));
|
||
|
}
|
||
|
|
||
|
properties.put("bmp_version", "BMP v. 3.x");
|
||
|
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)readDWord(inputStream);
|
||
|
greenMask = (int)readDWord(inputStream);
|
||
|
blueMask = (int)readDWord(inputStream);
|
||
|
|
||
|
properties.put("red_mask", new Integer(redMask));
|
||
|
properties.put("green_mask", new Integer(greenMask));
|
||
|
properties.put("blue_mask", new Integer(blueMask));
|
||
|
|
||
|
if (colorsUsed != 0) {
|
||
|
// there is a palette
|
||
|
sizeOfPalette = (int)colorsUsed*4;
|
||
|
palette = new byte[sizeOfPalette];
|
||
|
inputStream.read(palette, 0, sizeOfPalette);
|
||
|
properties.put("palette", palette);
|
||
|
}
|
||
|
|
||
|
properties.put("bmp_version", "BMP v. 3.x NT");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder1"));
|
||
|
}
|
||
|
} else if (size == 108) {
|
||
|
// Windows 4.x BMP
|
||
|
|
||
|
properties.put("bmp_version", "BMP v. 4.x");
|
||
|
|
||
|
// rgb masks, valid only if comp is BI_BITFIELDS
|
||
|
redMask = (int)readDWord(inputStream);
|
||
|
greenMask = (int)readDWord(inputStream);
|
||
|
blueMask = (int)readDWord(inputStream);
|
||
|
// Only supported for 32bpp BI_RGB argb
|
||
|
alphaMask = (int)readDWord(inputStream);
|
||
|
long csType = readDWord(inputStream);
|
||
|
int redX = readLong(inputStream);
|
||
|
int redY = readLong(inputStream);
|
||
|
int redZ = readLong(inputStream);
|
||
|
int greenX = readLong(inputStream);
|
||
|
int greenY = readLong(inputStream);
|
||
|
int greenZ = readLong(inputStream);
|
||
|
int blueX = readLong(inputStream);
|
||
|
int blueY = readLong(inputStream);
|
||
|
int blueZ = readLong(inputStream);
|
||
|
long gammaRed = readDWord(inputStream);
|
||
|
long gammaGreen = readDWord(inputStream);
|
||
|
long gammaBlue = readDWord(inputStream);
|
||
|
|
||
|
// Read in the palette
|
||
|
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
|
||
|
int sizeOfPalette = numberOfEntries*4;
|
||
|
palette = new byte[sizeOfPalette];
|
||
|
inputStream.read(palette, 0, sizeOfPalette);
|
||
|
|
||
|
if (palette != null || palette.length != 0) {
|
||
|
properties.put("palette", palette);
|
||
|
}
|
||
|
|
||
|
switch((int)csType) {
|
||
|
case LCS_CALIBRATED_RGB:
|
||
|
// All the new fields are valid only for this case
|
||
|
properties.put("color_space", "LCS_CALIBRATED_RGB");
|
||
|
properties.put("redX", new Integer(redX));
|
||
|
properties.put("redY", new Integer(redY));
|
||
|
properties.put("redZ", new Integer(redZ));
|
||
|
properties.put("greenX", new Integer(greenX));
|
||
|
properties.put("greenY", new Integer(greenY));
|
||
|
properties.put("greenZ", new Integer(greenZ));
|
||
|
properties.put("blueX", new Integer(blueX));
|
||
|
properties.put("blueY", new Integer(blueY));
|
||
|
properties.put("blueZ", new Integer(blueZ));
|
||
|
properties.put("gamma_red", new Long(gammaRed));
|
||
|
properties.put("gamma_green", new Long(gammaGreen));
|
||
|
properties.put("gamma_blue", new Long(gammaBlue));
|
||
|
|
||
|
// break;
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder2"));
|
||
|
|
||
|
case LCS_sRGB:
|
||
|
// Default Windows color space
|
||
|
properties.put("color_space", "LCS_sRGB");
|
||
|
break;
|
||
|
|
||
|
case LCS_CMYK:
|
||
|
properties.put("color_space", "LCS_CMYK");
|
||
|
// break;
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder2"));
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
properties.put("red_mask", new Integer(redMask));
|
||
|
properties.put("green_mask", new Integer(greenMask));
|
||
|
properties.put("blue_mask", new Integer(blueMask));
|
||
|
properties.put("alpha_mask", new Integer(alphaMask));
|
||
|
} else {
|
||
|
properties.put("bmp_version", "BMP v. 5.x");
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder4"));
|
||
|
}
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new RuntimeException(JaiI18N.getString("BMPImageDecoder5"));
|
||
|
}
|
||
|
|
||
|
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.
|
||
|
tileWidth = width;
|
||
|
tileHeight = height;
|
||
|
|
||
|
// When number of bitsPerPixel is <= 8, we use IndexColorModel.
|
||
|
if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
|
||
|
|
||
|
numBands = 1;
|
||
|
|
||
|
if (bitsPerPixel == 8) {
|
||
|
sampleModel =
|
||
|
RasterFactory.createPixelInterleavedSampleModel(
|
||
|
DataBuffer.TYPE_BYTE,
|
||
|
width, height,
|
||
|
numBands);
|
||
|
} 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[];
|
||
|
int size;
|
||
|
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[size];
|
||
|
g = new byte[size];
|
||
|
b = new byte[size];
|
||
|
for (int i=0; i<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[size];
|
||
|
g = new byte[size];
|
||
|
b = new byte[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];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
colorModel = new IndexColorModel(bitsPerPixel, 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.getInstance(ColorSpace.CS_sRGB),
|
||
|
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.getInstance(ColorSpace.CS_sRGB),
|
||
|
32, redMask, greenMask, blueMask, alphaMask,
|
||
|
false, DataBuffer.TYPE_INT);
|
||
|
} else {
|
||
|
numBands = 3;
|
||
|
// Create SampleModel
|
||
|
sampleModel =
|
||
|
RasterFactory.createPixelInterleavedSampleModel(
|
||
|
DataBuffer.TYPE_BYTE, width, height, numBands);
|
||
|
|
||
|
colorModel =
|
||
|
ImageCodec.createComponentColorModel(sampleModel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Deal with 1 Bit images using IndexColorModels
|
||
|
private void read1Bit(byte[] bdata, int paletteEntries) {
|
||
|
|
||
|
int padding = 0;
|
||
|
int bytesPerScanline = (int)Math.ceil((double)width/8.0);
|
||
|
|
||
|
int remainder = bytesPerScanline % 4;
|
||
|
if (remainder != 0) {
|
||
|
padding = 4 - remainder;
|
||
|
}
|
||
|
|
||
|
int imSize = (bytesPerScanline + padding) * height;
|
||
|
|
||
|
// Read till we have the whole image
|
||
|
byte values[] = new byte[imSize];
|
||
|
try {
|
||
|
int bytesRead = 0;
|
||
|
while (bytesRead < imSize) {
|
||
|
bytesRead += inputStream.read(values, bytesRead,
|
||
|
imSize - bytesRead);
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
|
||
|
if (isBottomUp) {
|
||
|
|
||
|
// Convert the bottom up image to a top down format by copying
|
||
|
// one scanline from the bottom to the top at a time.
|
||
|
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(values,
|
||
|
imSize - (i+1)*(bytesPerScanline + padding),
|
||
|
bdata,
|
||
|
i*bytesPerScanline, bytesPerScanline);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(values,
|
||
|
i * (bytesPerScanline + padding),
|
||
|
bdata,
|
||
|
i * bytesPerScanline,
|
||
|
bytesPerScanline);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Method to read a 4 bit BMP image data
|
||
|
private void read4Bit(byte[] bdata, int paletteEntries) {
|
||
|
|
||
|
// Padding bytes at the end of each scanline
|
||
|
int padding = 0;
|
||
|
|
||
|
int bytesPerScanline = (int)Math.ceil((double)width/2.0);
|
||
|
int remainder = bytesPerScanline % 4;
|
||
|
if (remainder != 0) {
|
||
|
padding = 4 - remainder;
|
||
|
}
|
||
|
|
||
|
int imSize = (bytesPerScanline + padding) * height;
|
||
|
|
||
|
// Read till we have the whole image
|
||
|
byte values[] = new byte[imSize];
|
||
|
try {
|
||
|
int bytesRead = 0;
|
||
|
while (bytesRead < imSize) {
|
||
|
bytesRead += inputStream.read(values, bytesRead,
|
||
|
imSize - bytesRead);
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
|
||
|
if (isBottomUp) {
|
||
|
|
||
|
// Convert the bottom up image to a top down format by copying
|
||
|
// one scanline from the bottom to the top at a time.
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(values,
|
||
|
imSize - (i+1)*(bytesPerScanline + padding),
|
||
|
bdata,
|
||
|
i*bytesPerScanline,
|
||
|
bytesPerScanline);
|
||
|
}
|
||
|
} else {
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(values,
|
||
|
i * (bytesPerScanline + padding),
|
||
|
bdata,
|
||
|
i * bytesPerScanline,
|
||
|
bytesPerScanline);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Method to read 8 bit BMP image data
|
||
|
private void read8Bit(byte[] bdata, int paletteEntries) {
|
||
|
|
||
|
// Padding bytes at the end of each scanline
|
||
|
int padding = 0;
|
||
|
|
||
|
// width * bitsPerPixel should be divisible by 32
|
||
|
int bitsPerScanline = width * 8;
|
||
|
if ( bitsPerScanline%32 != 0) {
|
||
|
padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
|
||
|
padding = (int)Math.ceil(padding/8.0);
|
||
|
}
|
||
|
|
||
|
int imSize = (width + padding) * height;
|
||
|
|
||
|
// Read till we have the whole image
|
||
|
byte values[] = new byte[imSize];
|
||
|
try {
|
||
|
int bytesRead = 0;
|
||
|
while (bytesRead < imSize) {
|
||
|
bytesRead += inputStream.read(values, bytesRead,
|
||
|
imSize - bytesRead);
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
|
||
|
if (isBottomUp) {
|
||
|
|
||
|
// Convert the bottom up image to a top down format by copying
|
||
|
// one scanline from the bottom to the top at a time.
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(values,
|
||
|
imSize - (i+1) * (width + padding),
|
||
|
bdata,
|
||
|
i * width,
|
||
|
width);
|
||
|
}
|
||
|
} else {
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(values,
|
||
|
i * (width + padding),
|
||
|
bdata,
|
||
|
i * width,
|
||
|
width);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Method to read 24 bit BMP image data
|
||
|
private void read24Bit(byte[] bdata) {
|
||
|
// Padding bytes at the end of each scanline
|
||
|
int padding = 0;
|
||
|
|
||
|
// width * bitsPerPixel should be divisible by 32
|
||
|
int bitsPerScanline = width * 24;
|
||
|
if ( bitsPerScanline%32 != 0) {
|
||
|
padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
|
||
|
padding = (int)Math.ceil(padding/8.0);
|
||
|
}
|
||
|
|
||
|
int imSize = (int)imageSize;
|
||
|
if (imSize == 0) {
|
||
|
imSize = (int)(bitmapFileSize - bitmapOffset);
|
||
|
}
|
||
|
|
||
|
// Read till we have the whole image
|
||
|
byte values[] = new byte[imSize];
|
||
|
try {
|
||
|
int bytesRead = 0;
|
||
|
while (bytesRead < imSize) {
|
||
|
bytesRead += inputStream.read(values, bytesRead,
|
||
|
imSize - bytesRead);
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
// throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
throw new RuntimeException(ioe.getMessage());
|
||
|
}
|
||
|
|
||
|
int l=0, count;
|
||
|
|
||
|
if (isBottomUp) {
|
||
|
int max = width*height*3-1;
|
||
|
|
||
|
count = -padding;
|
||
|
for (int i=0; i<height; i++) {
|
||
|
l = max - (i+1)*width*3 + 1;
|
||
|
count += padding;
|
||
|
for (int j=0; j<width; j++) {
|
||
|
bdata[l++] = values[count++];
|
||
|
bdata[l++] = values[count++];
|
||
|
bdata[l++] = values[count++];
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
count = -padding;
|
||
|
for (int i=0; i<height; i++) {
|
||
|
count += padding;
|
||
|
for (int j=0; j<width; j++) {
|
||
|
bdata[l++] = values[count++];
|
||
|
bdata[l++] = values[count++];
|
||
|
bdata[l++] = values[count++];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void read16Bit(short sdata[]) {
|
||
|
// Padding bytes at the end of each scanline
|
||
|
int padding = 0;
|
||
|
|
||
|
// width * bitsPerPixel should be divisible by 32
|
||
|
int bitsPerScanline = width * 16;
|
||
|
if ( bitsPerScanline%32 != 0) {
|
||
|
padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
|
||
|
padding = (int)Math.ceil(padding/8.0);
|
||
|
}
|
||
|
|
||
|
int imSize = (int)imageSize;
|
||
|
if (imSize == 0) {
|
||
|
imSize = (int)(bitmapFileSize - bitmapOffset);
|
||
|
}
|
||
|
|
||
|
int l=0;
|
||
|
|
||
|
try {
|
||
|
if (isBottomUp) {
|
||
|
int max = width*height-1;
|
||
|
|
||
|
for (int i=0; i<height; i++) {
|
||
|
l = max - (i+1)*width + 1;
|
||
|
for (int j=0; j<width; j++) {
|
||
|
sdata[l++] = (short)(readWord(inputStream) & 0xffff);
|
||
|
}
|
||
|
for (int m=0; m<padding; m++) {
|
||
|
inputStream.read();
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
for (int i=0; i<height; i++) {
|
||
|
for (int j=0; j<width; j++) {
|
||
|
sdata[l++] = (short)(readWord(inputStream) & 0xffff);
|
||
|
}
|
||
|
for (int m=0; m<padding; m++) {
|
||
|
inputStream.read();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void read32Bit(int idata[]) {
|
||
|
int imSize = (int)imageSize;
|
||
|
if (imSize == 0) {
|
||
|
imSize = (int)(bitmapFileSize - bitmapOffset);
|
||
|
}
|
||
|
|
||
|
int l=0;
|
||
|
|
||
|
try {
|
||
|
if (isBottomUp) {
|
||
|
int max = width*height-1;
|
||
|
|
||
|
for (int i=0; i<height; i++) {
|
||
|
l = max - (i+1)*width + 1;
|
||
|
for (int j=0; j<width; j++) {
|
||
|
idata[l++] = (int)readDWord(inputStream);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
for (int i=0; i<height; i++) {
|
||
|
for (int j=0; j<width; j++) {
|
||
|
idata[l++] = (int)readDWord(inputStream);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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];
|
||
|
try {
|
||
|
int bytesRead = 0;
|
||
|
while (bytesRead < imSize) {
|
||
|
bytesRead += inputStream.read(values, bytesRead,
|
||
|
imSize - bytesRead);
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
|
||
|
// Since data is compressed, decompress it
|
||
|
byte val[] = decodeRLE8(imSize, padding, values);
|
||
|
|
||
|
// Uncompressed data does not have any padding
|
||
|
imSize = width * height;
|
||
|
|
||
|
if (isBottomUp) {
|
||
|
|
||
|
// Convert the bottom up image to a top down format by copying
|
||
|
// one scanline from the bottom to the top at a time.
|
||
|
// int bytesPerScanline = (int)Math.ceil((double)width/8.0);
|
||
|
int bytesPerScanline = width;
|
||
|
for (int i=0; i<height; i++) {
|
||
|
System.arraycopy(val,
|
||
|
imSize - (i+1)*(bytesPerScanline),
|
||
|
bdata,
|
||
|
i*bytesPerScanline, bytesPerScanline);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
bdata = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private byte[] decodeRLE8(int imSize, int padding, byte values[]) {
|
||
|
|
||
|
byte val[] = new byte[width * height];
|
||
|
int count = 0, l = 0;
|
||
|
int value;
|
||
|
boolean flag = false;
|
||
|
|
||
|
while (count != imSize) {
|
||
|
|
||
|
value = values[count++] & 0xff;
|
||
|
|
||
|
if (value == 0) {
|
||
|
switch(values[count++] & 0xff) {
|
||
|
|
||
|
case 0:
|
||
|
// End-of-scanline marker
|
||
|
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 (!isEven(end)) {
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
private int[] readRLE4() {
|
||
|
|
||
|
// 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
|
||
|
int values[] = new int[imSize];
|
||
|
try {
|
||
|
for (int i=0; i<imSize; i++) {
|
||
|
values[i] = inputStream.read();
|
||
|
}
|
||
|
} catch(IOException ioe) {
|
||
|
throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
|
||
|
}
|
||
|
|
||
|
// Decompress the RLE4 compressed data.
|
||
|
int val[] = decodeRLE4(imSize, padding, values);
|
||
|
|
||
|
// Invert it as it is bottom up format.
|
||
|
if (isBottomUp) {
|
||
|
|
||
|
int inverted[] = val;
|
||
|
val = new int[width * height];
|
||
|
int l = 0, index, lineEnd;
|
||
|
|
||
|
for (int i = height-1; i >= 0; i--) {
|
||
|
index = i * width;
|
||
|
lineEnd = l + width;
|
||
|
while(l != lineEnd) {
|
||
|
val[l++] = inverted[index++];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This array will be used to call setPixels as the decompression
|
||
|
// had unpacked the 4bit pixels each into an int.
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
private int[] decodeRLE4(int imSize, int padding, int values[]) {
|
||
|
|
||
|
int val[] = new int[width * height];
|
||
|
int count = 0, l = 0;
|
||
|
int value;
|
||
|
boolean flag = false;
|
||
|
|
||
|
while (count != imSize) {
|
||
|
|
||
|
value = values[count++];
|
||
|
|
||
|
if (value == 0) {
|
||
|
|
||
|
// Absolute mode
|
||
|
switch(values[count++]) {
|
||
|
|
||
|
case 0:
|
||
|
// End-of-scanline marker
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
// End-of-RLE marker
|
||
|
flag = true;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
// delta or vector marker
|
||
|
int xoff = values[count++];
|
||
|
int yoff = values[count];
|
||
|
// Move to the position xoff, yoff down
|
||
|
l += xoff + yoff*width;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
int end = values[count-1];
|
||
|
for (int i=0; i<end; i++) {
|
||
|
val[l++] = isEven(i) ? (values[count] & 0xf0) >> 4
|
||
|
: (values[count++] & 0x0f);
|
||
|
}
|
||
|
|
||
|
// When end is odd, the above for loop does not
|
||
|
// increment count, so do it now.
|
||
|
if (!isEven(end)) {
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
// Whenever end pixels can fit into odd number of bytes,
|
||
|
// an extra padding byte will be present, so skip that.
|
||
|
if ( !isEven((int)Math.ceil(end/2)) ) {
|
||
|
count++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
// Encoded mode
|
||
|
int alternate[] = { (values[count] & 0xf0) >> 4,
|
||
|
values[count] & 0x0f };
|
||
|
for (int i=0; i<value; i++) {
|
||
|
val[l++] = alternate[i%2];
|
||
|
}
|
||
|
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
// If End-of-RLE data, then exit the while loop
|
||
|
if (flag) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
private boolean isEven(int number) {
|
||
|
return (number%2 == 0 ? true : false);
|
||
|
}
|
||
|
|
||
|
// Windows defined data type reading methods - everything is little endian
|
||
|
|
||
|
// Unsigned 8 bits
|
||
|
private int readUnsignedByte(InputStream stream) throws IOException {
|
||
|
return (stream.read() & 0xff);
|
||
|
}
|
||
|
|
||
|
// Unsigned 2 bytes
|
||
|
private int readUnsignedShort(InputStream stream) throws IOException {
|
||
|
int b1 = readUnsignedByte(stream);
|
||
|
int b2 = readUnsignedByte(stream);
|
||
|
return ((b2 << 8) | b1) & 0xffff;
|
||
|
}
|
||
|
|
||
|
// Signed 16 bits
|
||
|
private int readShort(InputStream stream) throws IOException {
|
||
|
int b1 = readUnsignedByte(stream);
|
||
|
int b2 = readUnsignedByte(stream);
|
||
|
return (b2 << 8) | b1;
|
||
|
}
|
||
|
|
||
|
// Unsigned 16 bits
|
||
|
private int readWord(InputStream stream) throws IOException {
|
||
|
return readUnsignedShort(stream);
|
||
|
}
|
||
|
|
||
|
// Unsigned 4 bytes
|
||
|
private long readUnsignedInt(InputStream stream) throws IOException {
|
||
|
int b1 = readUnsignedByte(stream);
|
||
|
int b2 = readUnsignedByte(stream);
|
||
|
int b3 = readUnsignedByte(stream);
|
||
|
int b4 = readUnsignedByte(stream);
|
||
|
long l = (long)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
|
||
|
return l & 0xffffffff;
|
||
|
}
|
||
|
|
||
|
// Signed 4 bytes
|
||
|
private int readInt(InputStream stream) throws IOException {
|
||
|
int b1 = readUnsignedByte(stream);
|
||
|
int b2 = readUnsignedByte(stream);
|
||
|
int b3 = readUnsignedByte(stream);
|
||
|
int b4 = readUnsignedByte(stream);
|
||
|
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
|
||
|
}
|
||
|
|
||
|
// Unsigned 4 bytes
|
||
|
private long readDWord(InputStream stream) throws IOException {
|
||
|
return readUnsignedInt(stream);
|
||
|
}
|
||
|
|
||
|
// 32 bit signed value
|
||
|
private int readLong(InputStream stream) throws IOException {
|
||
|
return readInt(stream);
|
||
|
}
|
||
|
|
||
|
private synchronized Raster computeTile(int tileX, int tileY) {
|
||
|
if (theTile != null) {
|
||
|
return theTile;
|
||
|
}
|
||
|
|
||
|
// Create a new tile
|
||
|
Point org = new Point(tileXToX(tileX), tileYToY(tileY));
|
||
|
WritableRaster tile =
|
||
|
RasterFactory.createWritableRaster(sampleModel, org);
|
||
|
byte bdata[] = null; // buffer for byte data
|
||
|
short sdata[] = null; // buffer for short data
|
||
|
int idata[] = null; // buffer for int data
|
||
|
|
||
|
if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
|
||
|
bdata = (byte[])((DataBufferByte)tile.getDataBuffer()).getData();
|
||
|
else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
|
||
|
sdata = (short[])((DataBufferUShort)tile.getDataBuffer()).getData();
|
||
|
else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
|
||
|
idata = (int[])((DataBufferInt)tile.getDataBuffer()).getData();
|
||
|
|
||
|
// There should only be one tile.
|
||
|
switch(imageType) {
|
||
|
|
||
|
case VERSION_2_1_BIT:
|
||
|
// no compression
|
||
|
read1Bit(bdata, 3);
|
||
|
break;
|
||
|
|
||
|
case VERSION_2_4_BIT:
|
||
|
// no compression
|
||
|
read4Bit(bdata, 3);
|
||
|
break;
|
||
|
|
||
|
case VERSION_2_8_BIT:
|
||
|
// no compression
|
||
|
read8Bit(bdata, 3);
|
||
|
break;
|
||
|
|
||
|
case VERSION_2_24_BIT:
|
||
|
// no compression
|
||
|
read24Bit(bdata);
|
||
|
break;
|
||
|
|
||
|
case VERSION_3_1_BIT:
|
||
|
// 1-bit images cannot be compressed.
|
||
|
read1Bit(bdata, 4);
|
||
|
break;
|
||
|
|
||
|
case VERSION_3_4_BIT:
|
||
|
switch((int)compression) {
|
||
|
case BI_RGB:
|
||
|
read4Bit(bdata, 4);
|
||
|
break;
|
||
|
|
||
|
case BI_RLE4:
|
||
|
int pixels[] = readRLE4();
|
||
|
tile.setPixels(0, 0, width, height, pixels);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VERSION_3_8_BIT:
|
||
|
switch((int)compression) {
|
||
|
case BI_RGB:
|
||
|
read8Bit(bdata, 4);
|
||
|
break;
|
||
|
|
||
|
case BI_RLE8:
|
||
|
readRLE8(bdata);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
|
||
|
}
|
||
|
|
||
|
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_4_1_BIT:
|
||
|
read1Bit(bdata, 4);
|
||
|
break;
|
||
|
|
||
|
case VERSION_4_4_BIT:
|
||
|
switch((int)compression) {
|
||
|
|
||
|
case BI_RGB:
|
||
|
read4Bit(bdata, 4);
|
||
|
break;
|
||
|
|
||
|
case BI_RLE4:
|
||
|
int pixels[] = readRLE4();
|
||
|
tile.setPixels(0, 0, width, height, pixels);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
|
||
|
}
|
||
|
|
||
|
case VERSION_4_8_BIT:
|
||
|
switch((int)compression) {
|
||
|
|
||
|
case BI_RGB:
|
||
|
read8Bit(bdata, 4);
|
||
|
break;
|
||
|
|
||
|
case BI_RLE8:
|
||
|
readRLE8(bdata);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
throw new
|
||
|
RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
theTile = tile;
|
||
|
|
||
|
return tile;
|
||
|
}
|
||
|
|
||
|
public synchronized Raster getTile(int tileX, int tileY) {
|
||
|
if ((tileX != 0) || (tileY != 0)) {
|
||
|
throw new
|
||
|
IllegalArgumentException(JaiI18N.getString("BMPImageDecoder7"));
|
||
|
}
|
||
|
return computeTile(tileX, tileY);
|
||
|
}
|
||
|
}
|