Kaoru Onoe / BMPFile
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BMPFile.cpp Source File

BMPFile.cpp

00001 // ==================================================== Mar 04 2015, kayeks ==
00002 // BMPFile.cpp
00003 // ===========================================================================
00004 // File library for Bitmap images (*.bmp, *.dib).
00005 
00006 #include "BMPFile.h"
00007 
00008 const char* BMPFile::StatusString[] = {
00009     "Success",
00010     "NullFileName",
00011     "NoSuchFile",
00012     "NotABitmapFile",
00013     "UnsupportedFormat",
00014     "UnsupportedDepth",
00015     "AllocationFailed"
00016 };
00017 const char* BMPFile::FormatString[] = {
00018     "OS2_V1",
00019     "OS2_V2",
00020     "Windows_V3",
00021     "Windows_V4",
00022     "Windows_V5",
00023     "Unknown"
00024 };
00025 
00026 void BMPFile::readFile(FILE* fp, bool fetchData) {
00027     uint8_t  buf8[2];
00028     uint16_t buf16[2];
00029     uint32_t buf32[3];
00030     
00031     if (!fp) {
00032         status = NoSuchFile;
00033         return;
00034     }
00035     
00036     // (0 +2) Magic number ("BM")
00037     fread(buf8, 1, 2, fp);
00038     if (buf8[0] != 'B' || buf8[1] != 'M') {
00039         status = NotABitmapFile;
00040         fclose(fp);
00041         return;
00042     }
00043     
00044     // (2 +4) File size
00045     // (6 +4) Reserved area
00046     // (10 +4) Image data offset (unconfirmed)
00047     fread(buf32, 4, 3, fp);
00048     fileSize = buf32[0];
00049     
00050     // (14 +4) Header size
00051     fread(buf32, 4, 1, fp);
00052     switch (buf32[0]) {
00053     case 12:  // OS/2 V1 format
00054         format = OS2_V1;
00055         break;
00056     case 64:  // OS/2 V2 format
00057         format = OS2_V2;
00058         break;
00059     case 40:  // Windows V3 format
00060         format = Windows_V3;
00061         break;
00062     case 108:  // Windows V4 format
00063         format = Windows_V4;
00064         break;
00065     case 124:  // Windows V5 format
00066         format = Windows_V5;
00067         break;
00068     default:
00069         format = Unknown;
00070     }
00071     
00072     switch (format) {
00073     case OS2_V1:
00074         // (18 +2) Bitmap width
00075         // (20 +2) Bitmap height
00076         fread(buf16, 4, 2, fp);
00077         width = (uint32_t) buf16[0];
00078         height = (uint32_t) buf16[1];
00079         
00080         // (22 +2) Number of planes (unconfirmed)
00081         // (24 +2) Color depth
00082         fread(buf16, 2, 2, fp);
00083         colorDepth = buf16[1];
00084         switch (colorDepth) {
00085         case 1: case 4: case 8:
00086             paletteSize = paletteElemSize(format) * (1ul << colorDepth);
00087             break;
00088         case 16: case 24: case 32:  // No palette
00089             paletteSize = 0;
00090             break;
00091         default:
00092             paletteSize = 0;
00093             status = UnsupportedDepth;
00094             fclose(fp);
00095             return;
00096         }
00097         break;
00098     case Windows_V3:
00099         // (18 +4) Bitmap width
00100         // (22 +4) Bitmap height
00101         fread(buf32, 4, 2, fp);
00102         width = buf32[0];
00103         height = buf32[1];
00104         
00105         // (26 +2) Number of planes (unconfirmed)
00106         // (28 +2) Color depth
00107         fread(buf16, 2, 2, fp);
00108         colorDepth = buf16[1];
00109         switch (colorDepth) {
00110         case 1: case 4: case 8:
00111             paletteSize = paletteElemSize(format) * (1ul << colorDepth);
00112             break;
00113         case 16: case 24: case 32:  // No palette
00114             paletteSize = 0;
00115             break;
00116         default:
00117             paletteSize = 0;
00118             status = UnsupportedDepth;
00119             fclose(fp);
00120             return;
00121         }
00122         
00123         // (30 +4) Compression method (unconfirmed)
00124         // (34 +4) Bitmap data size (unconfirmed)
00125         // (38 +4) Horizontal resolution (unused)
00126         // (42 +4) Vertical resolution (unconfirmed)
00127         // (46 +4) Colors (unconfirmed)
00128         // (50 +4) Important colors (unconfirmed)
00129         fread(buf32, 4, 3, fp);
00130         fread(buf32, 4, 3, fp);
00131         break;
00132     case OS2_V2:
00133     case Windows_V4:
00134     case Windows_V5:
00135     case Unknown:
00136         status = UnsupportedFormat;
00137         fclose(fp);
00138         return;
00139     }
00140     
00141     // Allocate palette space if needed
00142     if (paletteSize) {
00143         palette = new uint8_t[paletteSize];
00144         
00145         // Read palette data
00146         fread(palette, 1, paletteSize, fp);
00147     }
00148     
00149     // Calculate stride / data length
00150     if (colorDepth == 1) {
00151         stride = ALIGN_BY_4((width + 7) / 8);
00152     } else if (colorDepth == 4) {
00153         stride = ALIGN_BY_4((width + 1) / 2);
00154     } else {
00155         // Color depth: 8, 16, 24, 32
00156         stride = ALIGN_BY_4(width * colorDepth / 8);
00157     }
00158     dataSize = stride * height;
00159     
00160     // Read image data
00161     if (fetchData) {
00162         readImageData(fp);
00163     }
00164     fclose(fp);
00165 }
00166 
00167 BMPFile::BMPFile(const char* filename, bool fetchData) {
00168     FILE* fp;
00169     
00170     status = Success;
00171     format = Unknown;
00172     fileSize = 0;
00173     paletteSize = 0;
00174     dataSize = 0;
00175     stride = 0;
00176     width = 0;
00177     height = 0;
00178     colorDepth = 0;
00179     palette = NULL;
00180     data = NULL;
00181     
00182     // Open file
00183     if (!filename) {
00184         status = NullFilename;
00185         return;
00186     }
00187     fp = fopen(filename, "rb");
00188     
00189     // Read file
00190     readFile(fp, fetchData);
00191 }
00192 
00193 BMPFile::BMPFile(FILE* fp, bool fetch) {
00194     status = Success;
00195     format = Unknown;
00196     fileSize = 0;
00197     paletteSize = 0;
00198     dataSize = 0;
00199     stride = 0;
00200     width = 0;
00201     height = 0;
00202     colorDepth = 0;
00203     palette = NULL;
00204     data = NULL;
00205     
00206     // Read file
00207     readFile(fp, fetch);
00208 }
00209 
00210 BMPFile::~BMPFile() {
00211     if (palette) {
00212         delete[] palette;
00213     }
00214     if (data) {
00215         delete[] data;
00216     }
00217 }
00218 
00219 void BMPFile::readImageData(FILE* fp) {
00220     // Allocate data space
00221     data = new uint8_t[dataSize];
00222     
00223     // Read bitmap data
00224     fread(data, 1, dataSize, fp);
00225 }
00226 
00227 uint32_t BMPFile::paletteElemSize(BMPFile::Format format) {
00228     switch (format) {
00229     case OS2_V1: case OS2_V2:
00230         // BGR888
00231         return 3;
00232     case Windows_V3: case Windows_V4: case Windows_V5:
00233         // BGRX8888
00234         return 4;
00235     default:
00236         return 0;
00237     }
00238 }
00239 
00240 int32_t BMPFile::paletteRed(uint8_t index) {
00241     if (!palette) {
00242         return -1;
00243     }
00244     switch (colorDepth) {
00245     case 1: case 4: case 8:
00246         if (index >= 1ul << colorDepth) {
00247             return -1;
00248         } else {
00249             return palette[paletteElemSize(format) * index + 2];
00250         }
00251     default:
00252         return -1;
00253     }
00254 }
00255 
00256 int32_t BMPFile::paletteGreen(uint8_t index) {
00257     if (!palette) {
00258         return -1;
00259     }
00260     switch (colorDepth) {
00261     case 1: case 4: case 8:
00262         if (index >= 1ul << colorDepth) {
00263             return -1;
00264         } else {
00265             return palette[paletteElemSize(format) * index + 1];
00266         }
00267     default:
00268         return -1;
00269     }
00270 }
00271 
00272 int32_t BMPFile::paletteBlue(uint8_t index) {
00273     if (!palette) {
00274         return -1;
00275     }
00276     switch (colorDepth) {
00277     case 1: case 4: case 8:
00278         if (index >= 1ul << colorDepth) {
00279             return -1;
00280         } else {
00281             return palette[paletteElemSize(format) * index];
00282         }
00283     default:
00284         return -1;
00285     }
00286 }
00287 
00288 int32_t BMPFile::red(uint32_t x, uint32_t y) {
00289     if (x >= width || y >= height) {
00290         return -1;
00291     }
00292     if (!data) {
00293         return -1;
00294     }
00295     switch (colorDepth) {
00296     case 1:  // Indexed from palette
00297         return paletteRed((data[stride * y + x / 8] >> 7 - x % 8) & 0x01);
00298     case 4:  // Indexed from palette
00299         return paletteRed((data[stride * y + x / 2] >> 4 * (1 - x % 2)) & 0x0f);
00300     case 8:  // Indexed from palette
00301         return paletteRed(data[stride * y + x]);
00302     case 16:  // BGR565 (bbbbbggg:gggrrrrr)
00303         return (data[stride * y + 2 * x + 1] & 0x1f) * 2;
00304     case 24:  // BGR888
00305         return data[stride * y + 3 * x + 2];
00306     case 32:  // BGRX8888
00307         return data[stride * y + 4 * x + 2];
00308     default:
00309         return -1;
00310     }
00311 }
00312 
00313 int32_t BMPFile::green(uint32_t x, uint32_t y) {
00314     if (x >= width || y >= height) {
00315         return -1;
00316     }
00317     if (!data) {
00318         return -1;
00319     }
00320     switch (colorDepth) {
00321     case 1:  // Indexed from palette
00322         return paletteGreen((data[stride * y + x / 8] >> 7 - x % 8) & 0x01);
00323     case 4:  // Indexed from palette
00324         return paletteGreen((data[stride * y + x / 2] >> 4 * (1 - x % 2)) & 0x0f);
00325     case 8:  // Indexed from palette
00326         return paletteGreen(data[stride * y + x]);
00327     case 16:  // BGR565 (bbbbbggg:gggrrrrr)
00328         return ((data[stride * y + 2 * x] & 0x07) << 3
00329                 | data[stride * y + 2 * x + 1] >> 5) * 2;
00330     case 24:  // BGR888
00331         return data[stride * y + 3 * x + 1];
00332     case 32:  // BGRX8888
00333         return data[stride * y + 4 * x + 1];
00334     default:
00335         return -1;
00336     }
00337 }
00338 
00339 int32_t BMPFile::blue(uint32_t x, uint32_t y) {
00340     if (x >= width || y >= height) {
00341         return -1;
00342     }
00343     if (!data) {
00344         return -1;
00345     }
00346     switch (colorDepth) {
00347     case 1:  // Indexed from palette
00348         return paletteBlue((data[stride * y + x / 8] >> 7 - x % 8) & 0x01);
00349     case 4:  // Indexed from palette
00350         return paletteBlue((data[stride * y + x / 2] >> 4 * (1 - x % 2)) & 0x0f);
00351     case 8:  // Indexed from palette
00352         return paletteBlue(data[stride * y + x]);
00353     case 16:  // RGB565 (bbbbbggg:gggrrrrr)
00354         return (data[stride * y + 2 * x] >> 3) * 2;
00355     case 24:  // BGR888
00356         return data[stride * y + 3 * x];
00357     case 32:  // BGRX8888
00358         return data[stride * y + 4 * x];
00359     default:
00360         return -1;
00361     }
00362 }