File library for Bitmap images (*.bmp, *.dib). Currently supports only Windows V3 format with 24-bit-per-pixel color depth.
Diff: BMPFile.cpp
- Revision:
- 1:8cf4beca9695
- Parent:
- 0:4617bf407fe5
- Child:
- 2:89b273c12b0a
diff -r 4617bf407fe5 -r 8cf4beca9695 BMPFile.cpp --- a/BMPFile.cpp Wed Mar 04 00:29:12 2015 +0000 +++ b/BMPFile.cpp Wed Mar 04 20:56:34 2015 +0000 @@ -15,11 +15,11 @@ "AllocationFailed" }; const char* BMPFile::FormatString[] = { + "OS2_V1", + "OS2_V2", "Windows_V3", "Windows_V4", "Windows_V5", - "OS2_V1", - "OS2_V2", "Unknown" }; @@ -28,15 +28,17 @@ uint8_t buf8[2]; uint16_t buf16[2]; uint32_t buf32[3]; - uint32_t offset; - + status = Success; format = Unknown; fileSize = 0; + paletteSize = 0; dataSize = 0; + stride = 0; width = 0; height = 0; colorDepth = 0; + palette = NULL; data = NULL; // Open file @@ -63,11 +65,16 @@ // (10 +4) Image data offset (unconfirmed) fread(buf32, 4, 3, fp); fileSize = buf32[0]; - offset = buf32[2]; // (14 +4) Header size fread(buf32, 4, 1, fp); switch (buf32[0]) { + case 12: // OS/2 V1 format + format = OS2_V1; + break; + case 64: // OS/2 V2 format + format = OS2_V2; + break; case 40: // Windows V3 format format = Windows_V3; break; @@ -77,17 +84,36 @@ case 124: // Windows V5 format format = Windows_V5; break; - case 12: // OS/2 V1 format - format = OS2_V1; - break; - case 64: // OS/2 V2 format - format = OS2_V2; - break; default: format = Unknown; } switch (format) { + case OS2_V1: + // (18 +2) Bitmap width + // (20 +2) Bitmap height + fread(buf16, 4, 2, fp); + width = (uint32_t) buf16[0]; + height = (uint32_t) buf16[1]; + + // (22 +2) Number of planes (unconfirmed) + // (24 +2) Color depth + fread(buf16, 2, 2, fp); + colorDepth = buf16[1]; + switch (colorDepth) { + case 1: case 4: case 8: + paletteSize = paletteElemSize(format) * (1ul << colorDepth); + break; + case 16: case 24: case 32: // No palette + paletteSize = 0; + break; + default: + paletteSize = 0; + status = UnsupportedDepth; + fclose(fp); + return; + } + break; case Windows_V3: // (18 +4) Bitmap width // (22 +4) Bitmap height @@ -99,7 +125,15 @@ // (28 +2) Color depth fread(buf16, 2, 2, fp); colorDepth = buf16[1]; - if (colorDepth != 24) { + switch (colorDepth) { + case 1: case 4: case 8: + paletteSize = paletteElemSize(format) * (1ul << colorDepth); + break; + case 16: case 24: case 32: // No palette + paletteSize = 0; + break; + default: + paletteSize = 0; status = UnsupportedDepth; fclose(fp); return; @@ -114,20 +148,33 @@ fread(buf32, 4, 3, fp); fread(buf32, 4, 3, fp); break; + case OS2_V2: case Windows_V4: case Windows_V5: - case OS2_V1: - case OS2_V2: case Unknown: status = UnsupportedFormat; fclose(fp); return; } - // Seek to image data offset - fseek(fp, offset, SEEK_SET); + + // Allocate palette space if needed + if (paletteSize) { + palette = new uint8_t[paletteSize]; + + // Read palette data + fread(palette, 1, paletteSize, fp); + } - // Calculate data length - dataSize = ((colorDepth / 8) * width + 3) / 4 * 4 * height; + // Calculate stride / data length + if (colorDepth == 1) { + stride = ALIGN_BY_4((width + 7) / 8); + } else if (colorDepth == 4) { + stride = ALIGN_BY_4((width + 1) / 2); + } else { + // Color depth: 8, 16, 24, 32 + stride = ALIGN_BY_4(width * colorDepth / 8); + } + dataSize = stride * height; // Allocate data space data = new uint8_t[dataSize]; @@ -139,7 +186,147 @@ } BMPFile::~BMPFile() { + if (palette) { + delete[] palette; + } if (data) { delete[] data; } } + +uint32_t BMPFile::paletteElemSize(BMPFile::Format format) { + switch (format) { + case OS2_V1: case OS2_V2: + // BGR888 + return 3; + case Windows_V3: case Windows_V4: case Windows_V5: + // BGRX8888 + return 4; + default: + return 0; + } +} + +int32_t BMPFile::paletteRed(uint8_t index) { + if (!palette) { + return -1; + } + switch (colorDepth) { + case 1: case 4: case 8: + if (index >= 1ul << colorDepth) { + return -1; + } else { + return palette[paletteElemSize(format) * index + 2]; + } + default: + return -1; + } +} + +int32_t BMPFile::paletteGreen(uint8_t index) { + if (!palette) { + return -1; + } + switch (colorDepth) { + case 1: case 4: case 8: + if (index >= 1ul << colorDepth) { + return -1; + } else { + return palette[paletteElemSize(format) * index + 1]; + } + default: + return -1; + } +} + +int32_t BMPFile::paletteBlue(uint8_t index) { + if (!palette) { + return -1; + } + switch (colorDepth) { + case 1: case 4: case 8: + if (index >= 1ul << colorDepth) { + return -1; + } else { + return palette[paletteElemSize(format) * index]; + } + default: + return -1; + } +} + +int32_t BMPFile::red(uint32_t x, uint32_t y) { + if (x >= width || y >= height) { + return -1; + } + if (!data) { + return -1; + } + switch (colorDepth) { + case 1: // Indexed from palette + return paletteRed((data[stride * y + x / 8] >> 7 - x % 8) & 0x01); + case 4: // Indexed from palette + return paletteRed((data[stride * y + x / 2] >> 4 * (1 - x % 2)) & 0x0f); + case 8: // Indexed from palette + return paletteRed(data[stride * y + x]); + case 16: // BGR565 (bbbbbggg:gggrrrrr) + return data[stride * y + 2 * x + 1] & 0x1f; + case 24: // BGR888 + return data[stride * y + 3 * x + 1]; + case 32: // BGRX8888 + return data[stride * y + 4 * x + 1]; + default: + return -1; + } +} + +int32_t BMPFile::green(uint32_t x, uint32_t y) { + if (x >= width || y >= height) { + return -1; + } + if (!data) { + return -1; + } + switch (colorDepth) { + case 1: // Indexed from palette + return paletteGreen((data[stride * y + x / 8] >> 7 - x % 8) & 0x01); + case 4: // Indexed from palette + return paletteGreen((data[stride * y + x / 2] >> 4 * (1 - x % 2)) & 0x0f); + case 8: // Indexed from palette + return paletteGreen(data[stride * y + x]); + case 16: // BGR565 (bbbbbggg:gggrrrrr) + return (data[stride * y + 2 * x] & 0x07) << 3 + | data[stride * y + 2 * x + 1] >> 5; + case 24: // BGR888 + return data[stride * y + 3 * x + 1]; + case 32: // BGRX8888 + return data[stride * y + 4 * x + 1]; + default: + return -1; + } +} + +int32_t BMPFile::blue(uint32_t x, uint32_t y) { + if (x >= width || y >= height) { + return -1; + } + if (!data) { + return -1; + } + switch (colorDepth) { + case 1: // Indexed from palette + return paletteBlue((data[stride * y + x / 8] >> 7 - x % 8) & 0x01); + case 4: // Indexed from palette + return paletteBlue((data[stride * y + x / 2] >> 4 * (1 - x % 2)) & 0x0f); + case 8: // Indexed from palette + return paletteBlue(data[stride * y + x]); + case 16: // RGB565 (bbbbbggg:gggrrrrr) + return data[stride * y + 2 * x] >> 3; + case 24: // BGR888 + return data[stride * y + 3 * x]; + case 32: // BGRX8888 + return data[stride * y + 4 * x]; + default: + return -1; + } +}