protected void Process(Stream stream, bool noHeader)
{
if (noHeader || stream is BufferedStream) {
inputStream = stream;
} else {
inputStream = new BufferedStream(stream);
}
if (!noHeader) {
// Start File Header
if (!(ReadUnsignedByte(inputStream) == 'B' &&
ReadUnsignedByte(inputStream) == 'M')) {
throw new Exception(MessageLocalization.GetComposedMessage("invalid.magic.value.for.bmp.file"));
}
// 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["color_planes"] = planes;
properties["bits_per_pixel"] = bitsPerPixel;
// As BMP always has 3 rgb bands, except for Version 5,
// which is bgra
numBands = 3;
if (bitmapOffset == 0)
bitmapOffset = size;
if (size == 12) {
// Windows 2.x and OS/2 1.x
properties["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;
if (bitmapOffset == size) {
switch (imageType) {
case VERSION_2_1_BIT:
sizeOfPalette = 2 * 3;
break;
case VERSION_2_4_BIT:
sizeOfPalette = 16 * 3;
break;
case VERSION_2_8_BIT:
sizeOfPalette = 256 * 3;
break;
case VERSION_2_24_BIT:
sizeOfPalette = 0;
break;
}
bitmapOffset = size + sizeOfPalette;
}
ReadPalette(sizeOfPalette);
} else {
compression = ReadDWord(inputStream);
imageSize = ReadDWord(inputStream);
xPelsPerMeter = ReadLong(inputStream);
yPelsPerMeter = ReadLong(inputStream);
long colorsUsed = ReadDWord(inputStream);
long colorsImportant = ReadDWord(inputStream);
switch ((int)compression) {
case BI_RGB:
properties["compression"] = "BI_RGB";
break;
case BI_RLE8:
properties["compression"] = "BI_RLE8";
break;
case BI_RLE4:
properties["compression"] = "BI_RLE4";
break;
case BI_BITFIELDS:
properties["compression"] = "BI_BITFIELDS";
break;
}
properties["x_pixels_per_meter"] = xPelsPerMeter;
properties["y_pixels_per_meter"] = yPelsPerMeter;
properties["colors_used"] = colorsUsed;
properties["colors_important"] = colorsImportant;
if (size == 40 || size == 52 || size == 56) {
// 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
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["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
}
// 52 and 56 byte header have mandatory R, G and B masks
if (size >= 52) {
redMask = (int)ReadDWord(inputStream);
greenMask = (int)ReadDWord(inputStream);
blueMask = (int)ReadDWord(inputStream);
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
}
// 56 byte header has mandatory alpha mask
if (size == 56) {
alphaMask = (int)ReadDWord(inputStream);
properties["alpha_mask"] = alphaMask;
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
if (bitmapOffset == size) {
switch (imageType) {
case VERSION_3_1_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4;
break;
case VERSION_3_4_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4;
break;
case VERSION_3_8_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4;
break;
default:
sizeOfPalette = 0;
break;
}
bitmapOffset = size + sizeOfPalette;
}
ReadPalette(sizeOfPalette);
properties["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);
// 56 byte header has mandatory alpha mask
if (size == 56)
{
alphaMask = (int)ReadDWord(inputStream);
properties["alpha_mask"] = alphaMask;
}
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
if (colorsUsed != 0) {
// there is a palette
sizeOfPalette = (int)colorsUsed*4;
ReadPalette(sizeOfPalette);
}
properties["bmp_version"] = "BMP v. 3.x NT";
break;
default:
throw new
Exception("Invalid compression specified in BMP file.");
}
} else if (size == 108) {
// Windows 4.x BMP
properties["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);
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["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
properties["alpha_mask"] = alphaMask;
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
if (bitmapOffset == size) {
switch (imageType) {
case VERSION_4_1_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4;
break;
case VERSION_4_4_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4;
break;
case VERSION_4_8_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4;
break;
default:
sizeOfPalette = 0;
break;
}
bitmapOffset = size + sizeOfPalette;
}
ReadPalette(sizeOfPalette);
switch ((int)csType) {
case LCS_CALIBRATED_RGB:
// All the new fields are valid only for this case
properties["color_space"] = "LCS_CALIBRATED_RGB";
properties["redX"] = redX;
properties["redY"] = redY;
properties["redZ"] = redZ;
properties["greenX"] = greenX;
properties["greenY"] = greenY;
properties["greenZ"] = greenZ;
properties["blueX"] = blueX;
properties["blueY"] = blueY;
properties["blueZ"] = blueZ;
properties["gamma_red"] = gammaRed;
properties["gamma_green"] = gammaGreen;
properties["gamma_blue"] = gammaBlue;
// break;
throw new
Exception("Not implemented yet.");
case LCS_sRGB:
// Default Windows color space
properties["color_space"] = "LCS_sRGB";
break;
case LCS_CMYK:
properties["color_space"] = "LCS_CMYK";
// break;
throw new
Exception("Not implemented yet.");
}
} else {
properties["bmp_version"] = "BMP v. 5.x";
throw new
Exception("BMP version 5 not implemented yet.");
}
}
if (height > 0) {
// bottom up image
isBottomUp = true;
} else {
// top down image
isBottomUp = false;
height = Math.Abs(height);
}
// When number of bitsPerPixel is <= 8, we use IndexColorModel.
if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
numBands = 1;
// Create IndexColorModel from the palette.
byte[] r;
byte[] g;
byte[] b;
int sizep;
if (imageType == VERSION_2_1_BIT ||
imageType == VERSION_2_4_BIT ||
imageType == VERSION_2_8_BIT) {
sizep = palette.Length/3;
if (sizep > 256) {
sizep = 256;
}
int off;
r = new byte[sizep];
g = new byte[sizep];
b = new byte[sizep];
for (int i=0; i<sizep; i++) {
off = 3 * i;
b[i] = palette[off];
g[i] = palette[off+1];
r[i] = palette[off+2];
}
} else {
sizep = palette.Length/4;
if (sizep > 256) {
sizep = 256;
}
int off;
r = new byte[sizep];
g = new byte[sizep];
b = new byte[sizep];
for (int i=0; i<sizep; i++) {
off = 4 * i;
b[i] = palette[off];
g[i] = palette[off+1];
r[i] = palette[off+2];
}
}
} else if (bitsPerPixel == 16) {
numBands = 3;
} else if (bitsPerPixel == 32) {
numBands = alphaMask == 0 ? 3 : 4;
} else {
numBands = 3;
}
}