/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/** This 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 <code>ImageReadParam</code>.
*
* This class supports Microsoft Windows Bitmap Version 3-5,
* as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
*/
// BMP Image types
// BMP variables
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;
/** The input stream where reads from */
/** Indicates whether the header is read. */
private boolean gotHeader = false;
/** The original image width. */
private int width;
/** The original image height. */
private int height;
/** The destination region. */
/** The source region. */
/** The metadata from the stream. */
/** The destination image. */
/** Indicates whether subsampled, subregion is required, and offset is
* defined
*/
private boolean noTransform = true;
/** Indicates whether subband is selected. */
private boolean seleBand = false;
/** The scaling factors. */
/** source and destination bands. */
/** Constructs <code>BMPImageReader</code> from the provided
* <code>ImageReaderSpi</code>.
*/
super(originator);
}
/** Overrides the method defined in the superclass. */
boolean seekForwardOnly,
boolean ignoreMetadata) {
}
/** Overrides the method defined in the superclass. */
}
if (seekForwardOnly && allowSearch) {
}
return 1;
}
readHeader();
return width;
}
readHeader();
return height;
}
if (imageIndex != 0) {
}
}
if (gotHeader)
return;
throw new IllegalStateException("Input source not set!");
}
this.metadata = new BMPMetadata();
// read and check the magic marker
byte[] marker = new byte[2];
// Read file size
// skip the two reserved fields
// Offset to the bitmap from the beginning
// End File Header
// Start BitmapCoreHeader
if (size == 12) {
} else {
}
//metadata.colorPlane = planes;
// 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
// Classify the image type
if (bitsPerPixel == 1) {
} else if (bitsPerPixel == 4) {
} else if (bitsPerPixel == 8) {
} else if (bitsPerPixel == 24) {
}
// Read in the palette
palette = new byte[sizeOfPalette];
} else {
if (size == 40) {
// Windows 3.x and Windows NT
switch((int)compression) {
case BI_JPEG:
case BI_PNG:
break;
case BI_RGB: // No compression
case BI_RLE8: // 8-bit RLE compression
case BI_RLE4: // 4-bit RLE compression
// Read in the palette
palette = new byte[sizeOfPalette];
if (bitsPerPixel == 1) {
} else if (bitsPerPixel == 4) {
} else if (bitsPerPixel == 8) {
} else if (bitsPerPixel == 24) {
} else if (bitsPerPixel == 16) {
redMask = 0x7C00;
greenMask = 0x3E0;
} else if (bitsPerPixel == 32) {
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
}
break;
case BI_BITFIELDS:
if (bitsPerPixel == 16) {
} else if (bitsPerPixel == 32) {
}
// BitsField encoding
if (colorsUsed != 0) {
// there is a palette
palette = new byte[sizeOfPalette];
}
break;
default:
throw new
}
// Windows 4.x BMP
if (size == 108)
else if (size == 124)
// rgb masks, valid only if comp is BI_BITFIELDS
// Only supported for 32bpp BI_RGB argb
if (size == 124) {
}
if (csType == LCS_CALIBRATED_RGB) {
// All the new fields are valid only for this case
}
// Read in the palette
palette = new byte[sizeOfPalette];
switch ((int)compression) {
case BI_JPEG:
case BI_PNG:
if (size == 108) {
} else if (size == 124) {
}
break;
default:
if (bitsPerPixel == 1) {
} else if (bitsPerPixel == 4) {
} else if (bitsPerPixel == 8) {
} else if (bitsPerPixel == 16) {
if ((int)compression == BI_RGB) {
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = 0x1F;
}
} else if (bitsPerPixel == 24) {
} else if (bitsPerPixel == 32) {
if ((int)compression == BI_RGB) {
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
}
}
}
} else {
throw new
}
}
if (height > 0) {
// bottom up image
isBottomUp = true;
} else {
// top down image
isBottomUp = false;
}
// Reset Image Layout so there's only one tile.
//Define the color space
byte[] profile = new byte[profileSize];
try {
{
} else {
}
} catch (Exception e) {
}
}
if (bitsPerPixel == 0 ||
{
// the colorModel and sampleModel will be initialzed
// by the reader of embedded image
colorModel = null;
sampleModel = null;
// 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++) {
}
} else {
// 1 and 4 bit pixels can be stored in a packed format.
}
// 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) {
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;
}
} else {
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;
}
}
if (ImageUtil.isIndicesForGrayscale(r, g, b))
else
} else if (bitsPerPixel == 16) {
numBands = 3;
false, DataBuffer.TYPE_USHORT);
} else if (bitsPerPixel == 32) {
// The number of bands in the SampleModel is determined by
// the length of the mask array passed in.
bitMasks);
false, DataBuffer.TYPE_INT);
} else {
numBands = 3;
// Create SampleModel
int[] bandOffsets = new int[numBands];
for (int i = 0; i < numBands; i++) {
}
}
// Reset to the start of bitmap; then jump to the
//start of image data
gotHeader = true;
}
throws IOException {
readHeader();
}
return new ImageReadParam();
}
throws IOException {
readHeader();
}
return metadata;
}
return null;
}
readHeader();
}
throws IOException {
}
param = getDefaultReadParam();
//read header
readHeader();
// If the destination band is set used it
if (!seleBand) {
sourceBands = 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
// Get the image data.
if (seleBand)
}
} else {
}
// the sampleModel can be null in case of embedded image
if (sampleModel != null) {
bdata = (byte[])
sdata = (short[])
idata = (int[])
}
// There should only be one tile.
switch(imageType) {
case VERSION_2_1_BIT:
// no compression
break;
case VERSION_2_4_BIT:
// no compression
break;
case VERSION_2_8_BIT:
// no compression
break;
case VERSION_2_24_BIT:
// no compression
break;
case VERSION_3_1_BIT:
// 1-bit images cannot be compressed.
break;
case VERSION_3_4_BIT:
switch((int)compression) {
case BI_RGB:
break;
case BI_RLE4:
break;
default:
throw new
}
break;
case VERSION_3_8_BIT:
switch((int)compression) {
case BI_RGB:
break;
case BI_RLE8:
break;
default:
throw new
}
break;
case VERSION_3_24_BIT:
// 24-bit images are not compressed
break;
case VERSION_3_NT_16_BIT:
break;
case VERSION_3_NT_32_BIT:
break;
case VERSION_3_XP_EMBEDDED:
case VERSION_4_XP_EMBEDDED:
case VERSION_5_XP_EMBEDDED:
break;
case VERSION_4_1_BIT:
break;
case VERSION_4_4_BIT:
switch((int)compression) {
case BI_RGB:
break;
case BI_RLE4:
break;
default:
throw new
}
case VERSION_4_8_BIT:
switch((int)compression) {
case BI_RGB:
break;
case BI_RLE8:
break;
default:
throw new
}
break;
case VERSION_4_16_BIT:
break;
case VERSION_4_24_BIT:
break;
case VERSION_4_32_BIT:
break;
}
if (abortRequested())
else
return bi;
}
public boolean canReadRaster() {
return true;
}
}
private void resetHeaderInfo() {
gotHeader = false;
}
public void reset() {
super.reset();
}
// Deal with 1 Bit images using IndexColorModels
if (padding != 0) {
}
if (noTransform) {
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
new int[]{0});
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
if (isBottomUp) {
int lastLine =
} else
// cache the values to avoid duplicated computation
i++, j++, x += scaleX) {
srcPos[j] = x >> 3;
destPos[j] = i >> 3;
}
int k = destinationRegion.y * lineStride;
if (isBottomUp)
for (int j = 0, y = sourceRegion.y;
if (abortRequested())
break;
//get the bit and assign to the data buffer of the raster
}
new int[]{0});
}
}
}
// Method to read a 4 bit BMP image data
// Padding bytes at the end of each scanline
if (padding != 0)
if (noTransform) {
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
new int[]{0});
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
if (isBottomUp) {
int lastLine =
} else
// cache the values to avoid duplicated computation
i++, j++, x += scaleX) {
srcPos[j] = x >> 1;
destPos[j] = i >> 1;
}
int k = destinationRegion.y * lineStride;
if (isBottomUp)
for (int j = 0, y = sourceRegion.y;
if (abortRequested())
break;
//get the bit and assign to the data buffer of the raster
}
new int[]{0});
}
}
}
// Method to read 8 bit BMP image data
// Padding bytes at the end of each scanline
if (padding != 0) {
}
if (noTransform) {
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
new int[]{0});
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
if (isBottomUp) {
int lastLine =
} else
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
if (abortRequested())
break;
for (int i = 0, m = sourceRegion.x;
//get the bit and assign to the data buffer of the raster
}
new int[]{0});
}
}
}
// Method to read 24 bit BMP image data
// Padding bytes at the end of each scanline
// width * bitsPerPixel should be divisible by 32
if ( padding != 0)
if (noTransform) {
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
new int[]{0});
}
} else {
byte[] buf = new byte[lineLength];
if (isBottomUp) {
int lastLine =
} else
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += destinationRegion.x * 3;
for (int j = 0, y = sourceRegion.y;
if (abortRequested())
break;
//get the bit and assign to the data buffer of the raster
int n = 3 * i + k;
}
new int[]{0});
}
}
}
// Padding bytes at the end of each scanline
// width * bitsPerPixel should be divisible by 32
if ( padding != 0)
if (noTransform) {
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
new int[]{0});
}
} else {
short[] buf = new short[lineLength];
int lineStride =
if (isBottomUp) {
int lastLine =
} else
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
if (abortRequested())
break;
for (int i = 0, m = sourceRegion.x;
//get the bit and assign to the data buffer of the raster
}
new int[]{0});
}
}
}
if (noTransform) {
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
new int[]{0});
}
} else {
int lineStride =
if (isBottomUp) {
int lastLine =
} else
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
if (abortRequested())
break;
for (int i = 0, m = sourceRegion.x;
//get the bit and assign to the data buffer of the raster
}
new int[]{0});
}
}
}
// If imageSize field is not provided, calculate it.
if (imSize == 0) {
}
int padding = 0;
// If width is not 32 bit aligned, then while uncompressing each
// scanline will have padding bytes, calculate the amount of padding
if (remainder != 0) {
}
// Read till we have the whole image
int bytesRead = 0;
// Since data is compressed, decompress it
}
int padding,
byte[] values,
byte[] bdata) throws IOException {
int value;
boolean flag = false;
int lineStride =
int finished = 0;
if (value == 0) {
case 0:
// End-of-scanline marker
if (lineNo >= sourceRegion.y &&
if (noTransform) {
for(int i = 0; i < width; i++)
new int[]{0});
finished++;
pos += destinationRegion.x;
for (int i = sourceRegion.x;
i += scaleX)
new int[]{0});
finished++;
}
}
l = 0;
if (abortRequested()) {
flag = true;
}
break;
case 1:
// End-of-RLE marker
flag = true;
break;
case 2:
// delta or vector marker
// Move to the position xoff, yoff down
break;
default:
for (int i=0; i<end; i++) {
}
// Whenever end pixels can fit into odd number of bytes,
// an extra padding byte will be present, so skip that.
count++;
}
}
} else {
for (int i=0; i<value; i++) {
}
count++;
}
// If End-of-RLE data, then exit the while loop
if (flag) {
break;
}
}
}
// If imageSize field is not specified, calculate it.
if (imSize == 0) {
}
int padding = 0;
// If width is not 32 byte aligned, then while uncompressing each
// scanline will have padding bytes, calculate the amount of padding
if (remainder != 0) {
}
// Read till we have the whole image
// Decompress the RLE4 compressed data.
}
int padding,
byte[] values,
byte[] bdata) throws IOException {
int value;
boolean flag = false;
int lineStride =
int finished = 0;
if (value == 0) {
// Absolute mode
case 0:
// End-of-scanline marker
// End-of-scanline marker
if (lineNo >= sourceRegion.y &&
if (noTransform) {
new int[]{0});
finished++;
for (int i = sourceRegion.x;
i += scaleX) {
shift += 4;
if (shift == 4) {
pos++;
}
shift &= 7;
}
new int[]{0});
finished++;
}
}
l = 0;
if (abortRequested()) {
flag = true;
}
break;
case 1:
// End-of-RLE marker
flag = true;
break;
case 2:
// delta or vector marker
// Move to the position xoff, yoff down
break;
default:
for (int i=0; i<end; i++) {
}
// When end is odd, the above for loop does not
// increment count, so do it now.
count++;
}
// Whenever end pixels can fit into odd number of bytes,
// an extra padding byte will be present, so skip that.
count++;
}
break;
}
} else {
// Encoded mode
}
count++;
}
// If End-of-RLE data, then exit the while loop
if (flag) {
break;
}
}
}
* ImageIO-style plugin.
*
* @param bi The destination <code>BufferedImage</code>.
* @param bmpParam The <code>ImageReadParam</code> for decoding this
* BMP image. The parameters for subregion, band selection and
* subsampling are used in decoding the jpeg image.
*/
throws IOException {
switch(type) {
case BI_JPEG:
format = "JPEG";
break;
case BI_PNG:
format = "PNG";
break;
default:
throw new
}
" " + format);
}
// prepare input
}
float percentageDone)
{
}
});
int[] bands)
{
}
{
}
int pass,
int[] bands)
{
bands);
}
BufferedImage thumb) {}
int pass,
int[] bands) {}
int[] bands) {}
});
{
}
});
return bi;
}
}
private static boolean isLinkedProfileAllowed() {
if (isLinkedProfileDisabled == null) {
}
};
}
return !isLinkedProfileDisabled;
}
/**
* Verifies whether the byte array contans a unc path.
* Non-UNC path examples:
* c:\path\to\file - simple notation
* \\?\c:\path\to\file - long notation
*
* UNC path examples:
* \\server\share - a UNC path in simple notation
* \\?\UNC\server\share - a UNC path in long notation
* \\.\some\device - a path to device.
*/
private static boolean isUncOrDevicePath(byte[] p) {
if (isWindowsPlatform == null) {
}
};
}
if (!isWindowsPlatform) {
/* no need for the check on platforms except windows */
return false;
}
/* normalize prefix of the path */
if (p[0] == '/') p[0] = '\\';
if (p[1] == '/') p[1] = '\\';
if (p[3] == '/') p[3] = '\\';
if ((p[0] == '\\') && (p[1] == '\\')) {
if ((p[2] == '?') && (p[3] == '\\')) {
// long path: whether unc or local
return ((p[4] == 'U' || p[4] == 'u') &&
(p[5] == 'N' || p[5] == 'n') &&
(p[6] == 'C' || p[6] == 'c'));
} else {
// device path or short unc notation
return true;
}
} else {
return false;
}
}
}