/** * Jingga * * @package Image * @copyright Dennis Eichhorn * @license OMS License 1.0 * @version 1.0.0 * @link https://jingga.app */ #ifndef IMAGE_BITMAP_H #define IMAGE_BITMAP_H #include "../Stdlib/Types.h" namespace Image { #define BITMAP_HEADER_SIZE 14 struct BitmapHeader { byte identifier[2]; // 2 bytes - bitmap identifier uint32 size; // 4 bytes - size in bytes byte app_data[4]; // 4 bytes - generated by the image software uint32 offset; // 4 bytes - defines starting address for pixels }; #define DIB_BITMAP_TYPE_BITMAPCOREHEADER 12 struct DIB_BITMAPCOREHEADER { uint32 size; uint16 width; uint16 height; uint16 color_planes; uint16 bits_per_pixel; }; #define DIB_BITMAP_TYPE_OS21XBITMAPHEADER DIB_BITMAP_TYPE_BITMAPCOREHEADER #define DIB_OS21XBITMAPHEADER DIB_BITMAPCOREHEADER #define DIB_BITMAP_TYPE_OS22XBITMAPHEADER 64 struct DIB_OS22XBITMAPHEADER { // @todo implement // They don't use a size as first value? how do I know if this is the correct header? }; #define DIB_BITMAP_TYPE_BITMAPINFOHEADER 40 struct DIB_BITMAPINFOHEADER { uint32 size; int32 width; int32 height; uint16 color_planes; uint16 bits_per_pixel; uint32 compression_method; uint32 raw_image_size; //int32 horizontal_ppm; //int32 vertical_ppm; uint32 color_palette; uint32 important_colors; }; #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_RGB 0x0000 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_RLE8 0x0001 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_RLE4 0x0002 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_BITFIELDS 0x0003 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_JPEG 0x0004 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_PNG 0x0005 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_ALPHABITFIELDS 0x0006 #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_CMYK 0x000B #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_CMYKRLE8 0x000C #define DIB_BITMAPINFOHEADER_COMPRESSION_BI_CMYKRLE4 0x000D #define DIB_BITMAPINFOHEADER_HALFTONING_NONE 0 #define DIB_BITMAPINFOHEADER_HALFTONING_ERROR_DIFFUSION 1 #define DIB_BITMAPINFOHEADER_HALFTONING_PANDA 2 #define DIB_BITMAPINFOHEADER_HALFTONING_SUPER_CIRCLE 3 #define DIB_BITMAP_TYPE_BITMAPV2INFOHEADER 52 struct DIB_BITMAPV2INFOHEADER { }; #define DIB_BITMAP_TYPE_BITMAPV3INFOHEADER 56 struct DIB_BITMAPV3INFOHEADER { }; struct CIEXYZ { int32 ciexyzX; int32 ciexyzY; int32 ciexyzZ; }; struct CIEXYZTRIPLE { CIEXYZ ciexyzRed; CIEXYZ ciexyzGreen; CIEXYZ ciexyzBlue; }; #define DIB_BITMAP_TYPE_BITMAPV4HEADER 108 struct DIB_BITMAPV4HEADER { int32 size; int32 width; int32 height; uint16 color_planes; uint16 bits_per_pixel; int32 compression_method; int32 raw_image_size; //int32 horizontal_ppm; //int32 vertical_ppm; uint32 color_palette; uint32 important_colors; int32 bV4RedMask; int32 bV4GreenMask; int32 bV4BlueMask; int32 bV4AlphaMask; int32 bV4CSType; CIEXYZTRIPLE bV4Endpoints; int32 bV4GammaRed; int32 bV4GammaGreen; int32 bV4GammaBlue; }; #define DIB_BITMAP_TYPE_BITMAPV5HEADER 124 struct DIB_BITMAPV5HEADER { int32 size; int32 width; int32 height; uint16 color_planes; uint16 bits_per_pixel; int32 compression_method; int32 raw_image_size; //int32 horizontal_ppm; //int32 vertical_ppm; uint32 color_palette; uint32 important_colors; int32 bV5RedMask; int32 bV5GreenMask; int32 bV5BlueMask; int32 bV5AlphaMask; int32 bV5CSType; CIEXYZTRIPLE bV5Endpoints; int32 bV5GammaRed; int32 bV5GammaGreen; int32 bV5GammaBlue; int32 bV5Intent; int32 bV5ProfileData; int32 bV5ProfileSize; int32 bV5Reserved; }; struct Bitmap { BitmapHeader header; byte dib_header_type; DIB_BITMAPINFOHEADER dib_header; // Despite the different header types we use this one for simplicity uint32* extra_bit_mask; // 3-4 = 12-16 bytes byte color_table_size; byte* color_table; // Pixels are stored in rows // Rows are padded in multiples of 4 bytes byte* pixels; byte* data; }; Bitmap generate_bitmap_references(byte* data) { Bitmap bitmap = {}; // Fill header bitmap.header.identifier[0] = *(data + 0); bitmap.header.identifier[1] = *(data + 1); bitmap.header.size = *((uint32 *) (data + 2)); bitmap.header.app_data[0] = *(data + 6); bitmap.header.app_data[1] = *(data + 7); bitmap.header.app_data[2] = *(data + 8); bitmap.header.app_data[3] = *(data + 9); bitmap.header.offset = *((uint32 *) (data + 10)); byte* dib_header_offset = data + BITMAP_HEADER_SIZE; bitmap.dib_header_type = *dib_header_offset; byte* color_table_offset = data + BITMAP_HEADER_SIZE + bitmap.dib_header_type; // Fill DIB header switch(bitmap.dib_header_type) { case DIB_BITMAP_TYPE_BITMAPCOREHEADER: { bitmap.dib_header.size = *((uint32 *) (dib_header_offset)); bitmap.dib_header.width = *((uint16 *) (dib_header_offset + 4)); bitmap.dib_header.height = *((uint16 *) (dib_header_offset + 6)); bitmap.dib_header.color_planes = *((uint16 *) (dib_header_offset + 8)); bitmap.dib_header.bits_per_pixel = *((uint16 *) (dib_header_offset + 10)); bitmap.dib_header.color_palette = 1U << bitmap.dib_header.bits_per_pixel; } break; case DIB_BITMAP_TYPE_BITMAPV5HEADER: case DIB_BITMAP_TYPE_BITMAPV4HEADER: case DIB_BITMAP_TYPE_BITMAPV3INFOHEADER: case DIB_BITMAP_TYPE_BITMAPV2INFOHEADER: case DIB_BITMAP_TYPE_BITMAPINFOHEADER: { bitmap.dib_header.size = *((uint32 *) (dib_header_offset)); bitmap.dib_header.width = *((int32 *) (dib_header_offset + 4)); bitmap.dib_header.height = *((int32 *) (dib_header_offset + 8)); bitmap.dib_header.color_planes = *((uint16 *) (dib_header_offset + 12)); bitmap.dib_header.bits_per_pixel = *((uint16 *) (dib_header_offset + 14)); bitmap.dib_header.compression_method = *((uint32 *) (dib_header_offset + 16)); bitmap.dib_header.raw_image_size = *((uint32 *) (dib_header_offset + 20)); bitmap.dib_header.color_palette = *((uint32 *) (dib_header_offset + 32)); bitmap.dib_header.important_colors = *((uint32 *) (dib_header_offset + 36)); if (bitmap.dib_header.compression_method == DIB_BITMAPINFOHEADER_COMPRESSION_BI_BITFIELDS) { // 12 bytes bitmap.extra_bit_mask = (uint32 *) (dib_header_offset + DIB_BITMAP_TYPE_BITMAPINFOHEADER); color_table_offset += 12; } else if (bitmap.dib_header.compression_method == DIB_BITMAPINFOHEADER_COMPRESSION_BI_ALPHABITFIELDS) { // 16 bytes bitmap.extra_bit_mask = (uint32 *) (dib_header_offset + DIB_BITMAP_TYPE_BITMAPINFOHEADER); color_table_offset += 16; } } break; default: { } } // Fill other bitmap.color_table = color_table_offset; bitmap.pixels = (byte *) (data + bitmap.header.offset); bitmap.data = data; return bitmap; } } #endif