#ifndef STIM_BMP_H #define STIM_BMP_H #include #include namespace stim { #pragma pack(1) typedef unsigned int DWORD; typedef unsigned short WORD; typedef signed int LONG; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER; const unsigned int DIB_BITMAPCOREHEADER = 12; const unsigned int DIB_OS21XBITMAPHEADER = 16; const unsigned int DIB_BITMAPINFOHEADER = 40; const unsigned int DIB_BITMAPV2INFOHEADER = 52; const unsigned int DIB_BITMAPV3INFOHEADER = 56; const unsigned int DIB_OS22XBITMAPHEADER = 64; const unsigned int DIB_BITMAPV4HEADER = 108; const unsigned int DIB_BITMAPV5HEADER = 124; typedef struct tagBITMAPCOREHEADER { DWORD bcSize; WORD bcWidth; WORD bcHeight; WORD bcPlanes; WORD bcBitCount; } BITMAPCOREHEADER, *PBITMAPCOREHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; //40 bytes LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; // From FileFormat.info typedef struct { DWORD Size; /* Size of this header in bytes */ LONG Width; /* Image width in pixels */ LONG Height; /* Image height in pixels */ WORD Planes; /* Number of color planes */ WORD BitsPerPixel; /* Number of bits per pixel */ DWORD Compression; /* Compression methods used */ DWORD SizeOfBitmap; /* Size of bitmap in bytes */ LONG HorzResolution; /* Horizontal resolution in pixels per meter */ LONG VertResolution; /* Vertical resolution in pixels per meter */ DWORD ColorsUsed; /* Number of colors in the image */ DWORD ColorsImportant; /* Minimum number of important colors */ /* Fields added for Windows 4.x follow this line */ DWORD RedMask; /* Mask identifying bits of red component */ DWORD GreenMask; /* Mask identifying bits of green component */ DWORD BlueMask; /* Mask identifying bits of blue component */ DWORD AlphaMask; /* Mask identifying bits of alpha component */ DWORD CSType; /* Color space type */ LONG RedX; /* X coordinate of red endpoint */ LONG RedY; /* Y coordinate of red endpoint */ LONG RedZ; /* Z coordinate of red endpoint */ LONG GreenX; /* X coordinate of green endpoint */ LONG GreenY; /* Y coordinate of green endpoint */ LONG GreenZ; /* Z coordinate of green endpoint */ LONG BlueX; /* X coordinate of blue endpoint */ LONG BlueY; /* Y coordinate of blue endpoint */ LONG BlueZ; /* Z coordinate of blue endpoint */ DWORD GammaRed; /* Gamma red coordinate scale value */ DWORD GammaGreen; /* Gamma green coordinate scale value */ DWORD GammaBlue; /* Gamma blue coordinate scale value */ } WIN4XBITMAPHEADER; typedef struct { DWORD bV5Size; LONG bV5Width; LONG bV5Height; WORD bV5Planes; WORD bV5BitCount; DWORD bV5Compression; DWORD bV5SizeImage; LONG bV5XPelsPerMeter; LONG bV5YPelsPerMeter; DWORD bV5ClrUsed; DWORD bV5ClrImportant; DWORD bV5RedMask; DWORD bV5GreenMask; DWORD bV5BlueMask; DWORD bV5AlphaMask; DWORD bV5CSType; LONG RedX; /* X coordinate of red endpoint */ LONG RedY; /* Y coordinate of red endpoint */ LONG RedZ; /* Z coordinate of red endpoint */ LONG GreenX; /* X coordinate of green endpoint */ LONG GreenY; /* Y coordinate of green endpoint */ LONG GreenZ; /* Z coordinate of green endpoint */ LONG BlueX; /* X coordinate of blue endpoint */ LONG BlueY; /* Y coordinate of blue endpoint */ LONG BlueZ; /* Z coordinate of blue endpoint */ DWORD bV5GammaRed; DWORD bV5GammaGreen; DWORD bV5GammaBlue; DWORD bV5Intent; DWORD bV5ProfileData; DWORD bV5ProfileSize; DWORD bV5Reserved; } BITMAPV5HEADER, *PBITMAPV5HEADER; //compression methods const unsigned int STIM_BI_RGB = 0; const unsigned int STIM_BI_BITFIELDS = 3; class bmp { std::ifstream file; public: unsigned int dib_header_size; size_t bit_pos; // start position (relative to the beginning of the file) of the bitmap bits size_t total_size; //total size of the bitmap file (in bytes) size_t width; size_t height; int channels; int bits_per_pixel; unsigned int compression; size_t bytes() { return width * height * bits_per_pixel / 8; } void read_bmpFileHeader() { BITMAPFILEHEADER file_header; file.read((char*)&file_header, sizeof(BITMAPFILEHEADER)); bit_pos = file_header.bfOffBits; total_size = file_header.bfSize; } void read_bmpCoreHeader() { tagBITMAPCOREHEADER header; file.read((char*)&header, sizeof(tagBITMAPCOREHEADER)); width = header.bcWidth; height = header.bcHeight; bits_per_pixel = header.bcBitCount; compression = 0; } void read_bmpInfoHeader() { tagBITMAPINFOHEADER info_header; file.read((char*)&info_header, sizeof(tagBITMAPINFOHEADER)); width = info_header.biWidth; height = info_header.biHeight; bits_per_pixel = info_header.biBitCount; compression = info_header.biCompression; } void read_bmpV4Header() { WIN4XBITMAPHEADER header; file.read((char*)&header, sizeof(WIN4XBITMAPHEADER)); width = header.Width; height = header.Height; bits_per_pixel = header.BitsPerPixel; compression = header.Compression; } void read_bmpV5Header() { BITMAPV5HEADER header; file.read((char*)&header, sizeof(BITMAPV5HEADER)); width = header.bV5Width; height = header.bV5Height; bits_per_pixel = header.bV5BitCount; compression = header.bV5Compression; } void read_dib() { //read the bitmap DIB information header std::streamoff header_pos = file.tellg(); file.read((char*)&dib_header_size, sizeof(unsigned int)); file.seekg(header_pos); switch (dib_header_size) { case DIB_BITMAPCOREHEADER: read_bmpCoreHeader(); break; case DIB_BITMAPINFOHEADER: read_bmpInfoHeader(); break; case DIB_BITMAPV4HEADER: read_bmpV4Header(); break; case DIB_BITMAPV5HEADER: read_bmpV5Header(); break; default: std::cout << "stim::bmp ERROR: this bitmap header format isn't supported" << std::endl; exit(1); } } bool open(std::string filename) { //open the bitmap file and read the header data file.open(filename, std::ifstream::binary); if (!file) { std::cout << "stim::bmp ERROR: error opening file: " << filename.c_str() << std::endl; return false; } read_bmpFileHeader(); //read the file header read_dib(); if (compression != STIM_BI_RGB) { //check for compression std::cout << "stim::bmp ERROR: this file is compressed, and compression is not supported" << std::endl; return false; } return true; } void close() { file.close(); } /// Copy the bitmap data into a pre-allocated array bool read(char* dst){ file.seekg(bit_pos); //seek to the beginning of the data array size_t row_bytes = width * bits_per_pixel / 8; //number of bytes in each row size_t padding = row_bytes % 4; //calculate the padding on disk for each row (rows must be multiples of 4) if(file){ for (size_t h = 0; h < height; h++) { //for each row in the image file.read(dst + (height - h - 1) * row_bytes, row_bytes); //read the row of image data file.seekg(padding, std::ios::cur); //seek to the end of the row on disk if (file.eof()) std::cout << "stim::bmp ERROR: array size incorrect, end of file reached while reading bitmap." << std::endl; else if (file.fail()) std::cout << "stim::bmp ERROR: reading bitmap array failed." << std::endl; else if (file.bad()) std::cout << "stim::bmp ERROR: stream integrity failed while reading bitmap array" << std::endl; } return true; } else{ std::cout<<"stim::bmp ERROR: could not read array from file."<