File library for Bitmap images (*.bmp, *.dib). Currently supports only Windows V3 format with 24-bit-per-pixel color depth.
BMPFile.cpp
- Committer:
- kayekss
- Date:
- 2015-04-05
- Revision:
- 3:be3e831a86c1
- Parent:
- 2:89b273c12b0a
File content as of revision 3:be3e831a86c1:
// ==================================================== Mar 04 2015, kayeks == // BMPFile.cpp // =========================================================================== // File library for Bitmap images (*.bmp, *.dib). #include "BMPFile.h" const char* BMPFile::StatusString[] = { "Success", "NullFileName", "NoSuchFile", "NotABitmapFile", "UnsupportedFormat", "UnsupportedDepth", "AllocationFailed" }; const char* BMPFile::FormatString[] = { "OS2_V1", "OS2_V2", "Windows_V3", "Windows_V4", "Windows_V5", "Unknown" }; void BMPFile::readFile(FILE* fp, bool fetchData) { uint8_t buf8[2]; uint16_t buf16[2]; uint32_t buf32[3]; if (!fp) { status = NoSuchFile; return; } // (0 +2) Magic number ("BM") fread(buf8, 1, 2, fp); if (buf8[0] != 'B' || buf8[1] != 'M') { status = NotABitmapFile; fclose(fp); return; } // (2 +4) File size // (6 +4) Reserved area // (10 +4) Image data offset (unconfirmed) fread(buf32, 4, 3, fp); fileSize = buf32[0]; // (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; case 108: // Windows V4 format format = Windows_V4; break; case 124: // Windows V5 format format = Windows_V5; 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 fread(buf32, 4, 2, fp); width = buf32[0]; height = buf32[1]; // (26 +2) Number of planes (unconfirmed) // (28 +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; } // (30 +4) Compression method (unconfirmed) // (34 +4) Bitmap data size (unconfirmed) // (38 +4) Horizontal resolution (unused) // (42 +4) Vertical resolution (unconfirmed) // (46 +4) Colors (unconfirmed) // (50 +4) Important colors (unconfirmed) fread(buf32, 4, 3, fp); fread(buf32, 4, 3, fp); break; case OS2_V2: case Windows_V4: case Windows_V5: case Unknown: status = UnsupportedFormat; fclose(fp); return; } // Allocate palette space if needed if (paletteSize) { palette = new uint8_t[paletteSize]; // Read palette data fread(palette, 1, paletteSize, fp); } // 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; // Read image data if (fetchData) { readImageData(fp); } fclose(fp); } BMPFile::BMPFile(const char* filename, bool fetchData) { FILE* fp; status = Success; format = Unknown; fileSize = 0; paletteSize = 0; dataSize = 0; stride = 0; width = 0; height = 0; colorDepth = 0; palette = NULL; data = NULL; // Open file if (!filename) { status = NullFilename; return; } fp = fopen(filename, "rb"); // Read file readFile(fp, fetchData); } BMPFile::BMPFile(FILE* fp, bool fetch) { status = Success; format = Unknown; fileSize = 0; paletteSize = 0; dataSize = 0; stride = 0; width = 0; height = 0; colorDepth = 0; palette = NULL; data = NULL; // Read file readFile(fp, fetch); } BMPFile::~BMPFile() { if (palette) { delete[] palette; } if (data) { delete[] data; } } void BMPFile::readImageData(FILE* fp) { // Allocate data space data = new uint8_t[dataSize]; // Read bitmap data fread(data, 1, dataSize, fp); } 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) * 2; case 24: // BGR888 return data[stride * y + 3 * x + 2]; case 32: // BGRX8888 return data[stride * y + 4 * x + 2]; 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) * 2; 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) * 2; case 24: // BGR888 return data[stride * y + 3 * x]; case 32: // BGRX8888 return data[stride * y + 4 * x]; default: return -1; } }