import java.lang.*; import java.io.*; import java.awt.*; import java.awt.image.*; final public class BitmapInputStream extends FilterInputStream { int _cx, _cy; int _cBitCount, _cBytesPerLine; int _aiPalettes[] = null; byte _abBuffer[] = null; final static String strInvalidFile = "BitmapInputStream: invalid file format"; // little endian functions; final static short readShort(byte ab[], int iIndex) { return (short)(((int)ab[iIndex] & 255) | (((int)ab[iIndex + 1] & 255) << 8)); } final static int readInt(byte ab[], int iIndex) { return ((int)ab[iIndex] & 255) | (((int)ab[iIndex + 1] & 255) << 8) | (((int)ab[iIndex + 2] & 255) << 16) | (((int)ab[iIndex + 3] & 255) << 24); } final static int readRGB(byte ab[], int iIndex) { return ((int)ab[iIndex] & 255) | (((int)ab[iIndex + 1] & 255) << 8) | (((int)ab[iIndex + 2] & 255) << 16); } final boolean readHeader(InputStream in) throws IOException { byte abFileHeader[] = new byte[Bitmap.FILE_HEADER_SIZE]; if (in.read(abFileHeader) != Bitmap.FILE_HEADER_SIZE && readShort(abFileHeader, Bitmap.USTYPE) != Bitmap.BITMAP_TYPE) { return false; } int infoHeaderSize = readInt(abFileHeader, Bitmap.OFFBITS) - Bitmap.FILE_HEADER_SIZE; byte abInfoHeader[] = new byte[infoHeaderSize]; if (in.read(abInfoHeader) != infoHeaderSize) { return false; } int cbFix; if ((cbFix = readInt(abInfoHeader, Bitmap.CBFIX)) == Bitmap.VER1_HEADER_SIZE) { if (readShort(abInfoHeader, Bitmap.CPLANES_1) != 1) { return false; } _cx = (int)readShort(abInfoHeader, Bitmap.CX_1); _cy = (int)readShort(abInfoHeader, Bitmap.CY_1); _cBitCount = (int)readShort(abInfoHeader, Bitmap.CBITCOUNT_1); if (_cBitCount == 1 || _cBitCount == 4 || _cBitCount == 8) { int cPalettes = 1 << _cBitCount; _aiPalettes = new int[cPalettes]; for (int iIndex = 0; iIndex < cPalettes; iIndex++) { _aiPalettes[iIndex] = readRGB(abInfoHeader, Bitmap.VER1_HEADER_SIZE + iIndex * 3); } } else if (_cBitCount != 24) { return false; } } else { if (readShort(abInfoHeader, Bitmap.CPLANES_2) != 1 || (cbFix >= (Bitmap.ULCOMPRESSION + 4) && readInt(abInfoHeader, Bitmap.ULCOMPRESSION) != 0)) { return false; } _cx = readInt(abInfoHeader, Bitmap.CX_2); _cy = readInt(abInfoHeader, Bitmap.CY_2); _cBitCount = (int)readShort(abInfoHeader, Bitmap.CBITCOUNT_2); if (_cBitCount == 1 || _cBitCount == 4 || _cBitCount == 8) { int cPalettes; if (cbFix < (Bitmap.CCLRUSED + 4) || (cPalettes = readInt(abInfoHeader, Bitmap.CCLRUSED)) == 0) { cPalettes = 1 << _cBitCount; } _aiPalettes = new int[cPalettes]; for (int iIndex = 0; iIndex < cPalettes; iIndex++) { _aiPalettes[iIndex] = readInt(abInfoHeader, cbFix + iIndex * 4); } } else if (_cBitCount != 24) { return false; } } _cBytesPerLine = ((_cx * _cBitCount + 31) & ~31) / 8; _abBuffer = new byte[_cBytesPerLine]; return true; } BitmapInputStream(InputStream in) throws IOException { super(in); if (!readHeader(in)) { throw new IOException(strInvalidFile); } } final public int xSize() { return _cx; } final public int ySize() { return _cy; } final public int bytesPerLine() { return _cBytesPerLine; } final public int[] readLine() throws IOException { int aiLine[] = new int[_cx]; in.read(_abBuffer); switch (_cBitCount) { case 1: { byte bPalette = 0; for (int x = 0; x < _cx; x++) { if ((x & 7) == 0) { bPalette = _abBuffer[x >>> 3]; } else { bPalette <<= 1; } aiLine[x] = _aiPalettes[(bPalette >>> 7) & 1]; } break; } case 4: { byte bPalette = 0; for (int x = 0; x < _cx; x++) { if ((x & 1) == 0) { bPalette = _abBuffer[x >>> 1]; } else { bPalette <<= 4; } aiLine[x] = _aiPalettes[(bPalette >>> 4) & 15]; } break; } case 8: for (int x = 0; x < _cx; x++) { aiLine[x] = _aiPalettes[(int)_abBuffer[x] & 255]; } break; default: for (int x = 0, iOffset = 0; x < _cx; x++) { aiLine[x] = (((int)_abBuffer[iOffset++] & 255) | (((int)_abBuffer[iOffset++] & 255) << 8) | (((int)_abBuffer[iOffset++] & 255) << 16)); } break; } return aiLine; } }