SD + Bitmap
Dependencies: TS_DISCO_F746NG LCD_DISCO_F746NG BSP_DISCO_F746NG
Diff: bitmap.h
- Revision:
- 0:14e97aa401f3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bitmap.h Tue May 21 10:24:03 2019 +0000 @@ -0,0 +1,774 @@ +/* + * Windows Bitmap File Loader + * Version 1.2.5 (20120929) + * + * Supported Formats: 1, 4, 8, 16, 24, 32 Bit Images + * Alpha Bitmaps are also supported. + * Supported compression types: RLE 8, BITFIELDS + * + * Created by: Benjamin Kalytta, 2006 - 2012 + * Thanks for bug fixes goes to: Chris Campbell + * + * Licence: Free to use, URL to my source and my name is required in your source code. + * + * Source can be found at http://www.kalytta.com/bitmap.h + * + * Warning: This code should not be used in unmodified form in a production environment. + * It should only serve as a basis for your own development. + * There is only a minimal error handling in this code. (Notice added 20111211) + */ + +#ifndef BITMAP_H +#define BITMAP_H + +#include <iostream> +#include <fstream> +#include <string> + +#ifndef __LITTLE_ENDIAN__ + #ifndef __BIG_ENDIAN__ + #define __LITTLE_ENDIAN__ + #endif +#endif + +#ifdef __LITTLE_ENDIAN__ + #define BITMAP_SIGNATURE 0x4d42 +#else + #define BITMAP_SIGNATURE 0x424d +#endif + +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) + typedef unsigned __int32 uint32_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int8 uint8_t; + typedef __int32 int32_t; +#elif defined(__GNUC__) || defined(__CYGWIN__) || defined(__MWERKS__) || defined(__WATCOMC__) || defined(__PGI) || defined(__LCC__) + #include <stdint.h> +#else + typedef unsigned int uint32_t; + typedef unsigned short int uint16_t; + typedef unsigned char uint8_t; + typedef int int32_t; +#endif + +#pragma pack(push, 1) + +typedef struct _BITMAP_FILEHEADER { + uint16_t Signature; + uint32_t Size; + uint32_t Reserved; + uint32_t BitsOffset; +} BITMAP_FILEHEADER; + +#define BITMAP_FILEHEADER_SIZE 14 + +typedef struct _BITMAP_HEADER { + uint32_t HeaderSize; + int32_t Width; + int32_t Height; + uint16_t Planes; + uint16_t BitCount; + uint32_t Compression; + uint32_t SizeImage; + int32_t PelsPerMeterX; + int32_t PelsPerMeterY; + uint32_t ClrUsed; + uint32_t ClrImportant; + uint32_t RedMask; + uint32_t GreenMask; + uint32_t BlueMask; + uint32_t AlphaMask; + uint32_t CsType; + uint32_t Endpoints[9]; // see http://msdn2.microsoft.com/en-us/library/ms536569.aspx + uint32_t GammaRed; + uint32_t GammaGreen; + uint32_t GammaBlue; +} BITMAP_HEADER; + +typedef struct _RGBA { + uint8_t Red; + uint8_t Green; + uint8_t Blue; + uint8_t Alpha; +} RGBA; + +typedef struct _BGRA { + uint8_t Blue; + uint8_t Green; + uint8_t Red; + uint8_t Alpha; +} BGRA; + +#pragma pack(pop) + +class CBitmap { +private: + BITMAP_FILEHEADER m_BitmapFileHeader; + BITMAP_HEADER m_BitmapHeader; + BGRA *m_BitmapData; + unsigned int m_BitmapSize; + + // Masks and bit counts shouldn't exceed 32 Bits +public: + class CColor { +public: + static inline unsigned int BitCountByMask(unsigned int Mask) { + unsigned int BitCount = 0; + while (Mask) { + Mask &= Mask - 1; + BitCount++; + } + return BitCount; + } + + static inline unsigned int BitPositionByMask(unsigned int Mask) { + return BitCountByMask((Mask & (~Mask + 1)) - 1); + } + + static inline unsigned int ComponentByMask(unsigned int Color, unsigned int Mask) { + unsigned int Component = Color & Mask; + return Component >> BitPositionByMask(Mask); + } + + static inline unsigned int BitCountToMask(unsigned int BitCount) { + return (BitCount == 32) ? 0xFFFFFFFF : (1 << BitCount) - 1; + } + + static unsigned int Convert(unsigned int Color, unsigned int FromBitCount, unsigned int ToBitCount) { + if (ToBitCount < FromBitCount) { + Color >>= (FromBitCount - ToBitCount); + } else { + Color <<= (ToBitCount - FromBitCount); + if (Color > 0) { + Color |= BitCountToMask(ToBitCount - FromBitCount); + } + } + return Color; + } + }; + +public: + + CBitmap() : m_BitmapData(0), m_BitmapSize(0) { + Dispose(); + } + + CBitmap(const char* Filename) : m_BitmapData(0), m_BitmapSize(0) { + Load(Filename); + } + + ~CBitmap() { + Dispose(); + } + + void Dispose() { + if (m_BitmapData) { + delete[] m_BitmapData; + m_BitmapData = 0; + } + memset(&m_BitmapFileHeader, 0, sizeof(m_BitmapFileHeader)); + memset(&m_BitmapHeader, 0, sizeof(m_BitmapHeader)); + } + + /* Load specified Bitmap and stores it as RGBA in an internal buffer */ + + bool Load(const char *Filename) { + std::ifstream file(Filename, std::ios::binary | std::ios::in); + + if (file.bad()) { + return false; + } + + if (file.is_open() == false) { + return false; + } + + Dispose(); + + file.read((char*) &m_BitmapFileHeader, BITMAP_FILEHEADER_SIZE); + if (m_BitmapFileHeader.Signature != BITMAP_SIGNATURE) { + return false; + } + + file.read((char*) &m_BitmapHeader, sizeof(BITMAP_HEADER)); + + /* Load Color Table */ + + file.seekg(BITMAP_FILEHEADER_SIZE + m_BitmapHeader.HeaderSize, std::ios::beg); + + unsigned int ColorTableSize = 0; + + if (m_BitmapHeader.BitCount == 1) { + ColorTableSize = 2; + } else if (m_BitmapHeader.BitCount == 4) { + ColorTableSize = 16; + } else if (m_BitmapHeader.BitCount == 8) { + ColorTableSize = 256; + } + + // Always allocate full sized color table + + BGRA* ColorTable = new BGRA[ColorTableSize]; // std::bad_alloc exception should be thrown if memory is not available + + file.read((char*) ColorTable, sizeof(BGRA) * m_BitmapHeader.ClrUsed); + + /* ... Color Table for 16 bits images are not supported yet */ + + m_BitmapSize = GetWidth() * GetHeight(); + m_BitmapData = new BGRA[m_BitmapSize]; + + unsigned int LineWidth = ((GetWidth() * GetBitCount() / 8) + 3) & ~3; + uint8_t *Line = new uint8_t[LineWidth]; + + file.seekg(m_BitmapFileHeader.BitsOffset, std::ios::beg); + + int Index = 0; + bool Result = true; + + if (m_BitmapHeader.Compression == 0) { + for (unsigned int i = 0; i < GetHeight(); i++) { + file.read((char*) Line, LineWidth); + + uint8_t *LinePtr = Line; + + for (unsigned int j = 0; j < GetWidth(); j++) { + if (m_BitmapHeader.BitCount == 1) { + uint32_t Color = *((uint8_t*) LinePtr); + for (int k = 0; k < 8; k++) { + m_BitmapData[Index].Red = ColorTable[Color & 0x80 ? 1 : 0].Red; + m_BitmapData[Index].Green = ColorTable[Color & 0x80 ? 1 : 0].Green; + m_BitmapData[Index].Blue = ColorTable[Color & 0x80 ? 1 : 0].Blue; + m_BitmapData[Index].Alpha = ColorTable[Color & 0x80 ? 1 : 0].Alpha; + Index++; + Color <<= 1; + } + LinePtr++; + j += 7; + } else if (m_BitmapHeader.BitCount == 4) { + uint32_t Color = *((uint8_t*) LinePtr); + m_BitmapData[Index].Red = ColorTable[(Color >> 4) & 0x0f].Red; + m_BitmapData[Index].Green = ColorTable[(Color >> 4) & 0x0f].Green; + m_BitmapData[Index].Blue = ColorTable[(Color >> 4) & 0x0f].Blue; + m_BitmapData[Index].Alpha = ColorTable[(Color >> 4) & 0x0f].Alpha; + Index++; + m_BitmapData[Index].Red = ColorTable[Color & 0x0f].Red; + m_BitmapData[Index].Green = ColorTable[Color & 0x0f].Green; + m_BitmapData[Index].Blue = ColorTable[Color & 0x0f].Blue; + m_BitmapData[Index].Alpha = ColorTable[Color & 0x0f].Alpha; + Index++; + LinePtr++; + j++; + } else if (m_BitmapHeader.BitCount == 8) { + uint32_t Color = *((uint8_t*) LinePtr); + m_BitmapData[Index].Red = ColorTable[Color].Red; + m_BitmapData[Index].Green = ColorTable[Color].Green; + m_BitmapData[Index].Blue = ColorTable[Color].Blue; + m_BitmapData[Index].Alpha = ColorTable[Color].Alpha; + Index++; + LinePtr++; + } else if (m_BitmapHeader.BitCount == 16) { + uint32_t Color = *((uint16_t*) LinePtr); + m_BitmapData[Index].Red = ((Color >> 10) & 0x1f) << 3; + m_BitmapData[Index].Green = ((Color >> 5) & 0x1f) << 3; + m_BitmapData[Index].Blue = (Color & 0x1f) << 3; + m_BitmapData[Index].Alpha = 255; + Index++; + LinePtr += 2; + } else if (m_BitmapHeader.BitCount == 24) { + uint32_t Color = *((uint32_t*) LinePtr); + m_BitmapData[Index].Blue = Color & 0xff; + m_BitmapData[Index].Green = (Color >> 8) & 0xff; + m_BitmapData[Index].Red = (Color >> 16) & 0xff; + m_BitmapData[Index].Alpha = 255; + Index++; + LinePtr += 3; + } else if (m_BitmapHeader.BitCount == 32) { + uint32_t Color = *((uint32_t*) LinePtr); + m_BitmapData[Index].Blue = Color & 0xff; + m_BitmapData[Index].Green = (Color >> 8) & 0xff; + m_BitmapData[Index].Red = (Color >> 16) & 0xff; + m_BitmapData[Index].Alpha = Color >> 24; + Index++; + LinePtr += 4; + } + } + } + } else if (m_BitmapHeader.Compression == 1) { // RLE 8 + uint8_t Count = 0; + uint8_t ColorIndex = 0; + int x = 0, y = 0; + + while (file.eof() == false) { + file.read((char*) &Count, sizeof(uint8_t)); + file.read((char*) &ColorIndex, sizeof(uint8_t)); + + if (Count > 0) { + Index = x + y * GetWidth(); + for (int k = 0; k < Count; k++) { + m_BitmapData[Index + k].Red = ColorTable[ColorIndex].Red; + m_BitmapData[Index + k].Green = ColorTable[ColorIndex].Green; + m_BitmapData[Index + k].Blue = ColorTable[ColorIndex].Blue; + m_BitmapData[Index + k].Alpha = ColorTable[ColorIndex].Alpha; + } + x += Count; + } else if (Count == 0) { + int Flag = ColorIndex; + if (Flag == 0) { + x = 0; + y++; + } else if (Flag == 1) { + break; + } else if (Flag == 2) { + char rx = 0; + char ry = 0; + file.read((char*) &rx, sizeof(char)); + file.read((char*) &ry, sizeof(char)); + x += rx; + y += ry; + } else { + Count = Flag; + Index = x + y * GetWidth(); + for (int k = 0; k < Count; k++) { + file.read((char*) &ColorIndex, sizeof(uint8_t)); + m_BitmapData[Index + k].Red = ColorTable[ColorIndex].Red; + m_BitmapData[Index + k].Green = ColorTable[ColorIndex].Green; + m_BitmapData[Index + k].Blue = ColorTable[ColorIndex].Blue; + m_BitmapData[Index + k].Alpha = ColorTable[ColorIndex].Alpha; + } + x += Count; + // Attention: Current Microsoft STL implementation seems to be buggy, tellg() always returns 0. + if (file.tellg() & 1) { + file.seekg(1, std::ios::cur); + } + } + } + } + } else if (m_BitmapHeader.Compression == 2) { // RLE 4 + /* RLE 4 is not supported */ + Result = false; + } else if (m_BitmapHeader.Compression == 3) { // BITFIELDS + + /* We assumes that mask of each color component can be in any order */ + + uint32_t BitCountRed = CColor::BitCountByMask(m_BitmapHeader.RedMask); + uint32_t BitCountGreen = CColor::BitCountByMask(m_BitmapHeader.GreenMask); + uint32_t BitCountBlue = CColor::BitCountByMask(m_BitmapHeader.BlueMask); + uint32_t BitCountAlpha = CColor::BitCountByMask(m_BitmapHeader.AlphaMask); + + for (unsigned int i = 0; i < GetHeight(); i++) { + file.read((char*) Line, LineWidth); + + uint8_t *LinePtr = Line; + + for (unsigned int j = 0; j < GetWidth(); j++) { + + uint32_t Color = 0; + + if (m_BitmapHeader.BitCount == 16) { + Color = *((uint16_t*) LinePtr); + LinePtr += 2; + } else if (m_BitmapHeader.BitCount == 32) { + Color = *((uint32_t*) LinePtr); + LinePtr += 4; + } else { + // Other formats are not valid + } + m_BitmapData[Index].Red = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.RedMask), BitCountRed, 8); + m_BitmapData[Index].Green = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.GreenMask), BitCountGreen, 8); + m_BitmapData[Index].Blue = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.BlueMask), BitCountBlue, 8); + m_BitmapData[Index].Alpha = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.AlphaMask), BitCountAlpha, 8); + + Index++; + } + } + } + + delete [] ColorTable; + delete [] Line; + + file.close(); + return Result; + } + + bool Save(const char* Filename, unsigned int BitCount = 32) { + bool Result = true; + + std::ofstream file(Filename, std::ios::out | std::ios::binary); + + if (file.is_open() == false) { + return false; + } + + BITMAP_FILEHEADER bfh; + BITMAP_HEADER bh; + memset(&bfh, 0, sizeof(bfh)); + memset(&bh, 0, sizeof(bh)); + + bfh.Signature = BITMAP_SIGNATURE; + bfh.BitsOffset = BITMAP_FILEHEADER_SIZE + sizeof(BITMAP_HEADER); + bfh.Size = (GetWidth() * GetHeight() * BitCount) / 8 + bfh.BitsOffset; + + bh.HeaderSize = sizeof(BITMAP_HEADER); + bh.BitCount = BitCount; + + if (BitCount == 32) { + bh.Compression = 3; // BITFIELD + bh.AlphaMask = 0xff000000; + bh.BlueMask = 0x00ff0000; + bh.GreenMask = 0x0000ff00; + bh.RedMask = 0x000000ff; + } else if (BitCount == 16) { + bh.Compression = 3; // BITFIELD + bh.AlphaMask = 0x00000000; + bh.BlueMask = 0x0000001f; + bh.GreenMask = 0x000007E0; + bh.RedMask = 0x0000F800; + } else { + bh.Compression = 0; // RGB + } + + unsigned int LineWidth = (GetWidth() + 3) & ~3; + + bh.Planes = 1; + bh.Height = GetHeight(); + bh.Width = GetWidth(); + bh.SizeImage = (LineWidth * BitCount * GetHeight()) / 8; + bh.PelsPerMeterX = 3780; + bh.PelsPerMeterY = 3780; + + if (BitCount == 32) { + file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER)); + file.write((char*) &bh, sizeof(BITMAP_HEADER)); + file.write((char*) m_BitmapData, bh.SizeImage); + } else if (BitCount < 16) { + uint8_t* Bitmap = new uint8_t[bh.SizeImage]; + + BGRA *Palette = 0; + unsigned int PaletteSize = 0; + + if (GetBitsWithPalette(Bitmap, bh.SizeImage, BitCount, Palette, PaletteSize)) { + bfh.BitsOffset += PaletteSize * sizeof(BGRA); + + file.write((char*) &bfh, BITMAP_FILEHEADER_SIZE); + file.write((char*) &bh, sizeof(BITMAP_HEADER)); + file.write((char*) Palette, PaletteSize * sizeof(BGRA)); + file.write((char*) Bitmap, bh.SizeImage); + } + delete [] Bitmap; + delete [] Palette; + } else { + uint32_t RedMask = 0; + uint32_t GreenMask = 0; + uint32_t BlueMask = 0; + uint32_t AlphaMask = 0; + + if (BitCount == 16) { + RedMask = 0x0000F800; + GreenMask = 0x000007E0; + BlueMask = 0x0000001F; + AlphaMask = 0x00000000; + } else if (BitCount == 24) { + RedMask = 0x00FF0000; + GreenMask = 0x0000FF00; + BlueMask = 0x000000FF; + } else { + // Other color formats are not valid + Result = false; + } + + if (Result) { + if (GetBits(NULL, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) { + uint8_t* Bitmap = new uint8_t[bh.SizeImage]; + if (GetBits(Bitmap, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) { + file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER)); + file.write((char*) &bh, sizeof(BITMAP_HEADER)); + file.write((char*) Bitmap, bh.SizeImage); + } + delete [] Bitmap; + } + } + } + + file.close(); + return Result; + } + + unsigned int GetWidth() { + /* Add plausibility test */ + // if (abs(m_BitmapHeader.Width) > 8192) { + // m_BitmapHeader.Width = 8192; + // } + return m_BitmapHeader.Width < 0 ? -m_BitmapHeader.Width : m_BitmapHeader.Width; + } + + unsigned int GetHeight() { + /* Add plausibility test */ + // if (abs(m_BitmapHeader.Height) > 8192) { + // m_BitmapHeader.Height = 8192; + // } + return m_BitmapHeader.Height < 0 ? -m_BitmapHeader.Height : m_BitmapHeader.Height; + } + + unsigned int GetBitCount() { + /* Add plausibility test */ + // if (m_BitmapHeader.BitCount > 32) { + // m_BitmapHeader.BitCount = 32; + // } + return m_BitmapHeader.BitCount; + } + + /* Copies internal RGBA buffer to user specified buffer */ + + bool GetBits(void* Buffer, unsigned int &Size) { + bool Result = false; + if (Size == 0 || Buffer == 0) { + Size = m_BitmapSize * sizeof(RGBA); + Result = m_BitmapSize != 0; + } else { + memcpy(Buffer, m_BitmapData, Size); + Result = true; + } + return Result; + } + + /* Returns internal RGBA buffer */ + + void* GetBits() { + return m_BitmapData; + } + + /* Copies internal RGBA buffer to user specified buffer and converts it into destination + * bit format specified by component masks. + * + * Typical Bitmap color formats (BGR/BGRA): + * + * Masks for 16 bit (5-5-5): ALPHA = 0x00000000, RED = 0x00007C00, GREEN = 0x000003E0, BLUE = 0x0000001F + * Masks for 16 bit (5-6-5): ALPHA = 0x00000000, RED = 0x0000F800, GREEN = 0x000007E0, BLUE = 0x0000001F + * Masks for 24 bit: ALPHA = 0x00000000, RED = 0x00FF0000, GREEN = 0x0000FF00, BLUE = 0x000000FF + * Masks for 32 bit: ALPHA = 0xFF000000, RED = 0x00FF0000, GREEN = 0x0000FF00, BLUE = 0x000000FF + * + * Other color formats (RGB/RGBA): + * + * Masks for 32 bit (RGBA): ALPHA = 0xFF000000, RED = 0x000000FF, GREEN = 0x0000FF00, BLUE = 0x00FF0000 + * + * Bit count will be rounded to next 8 bit boundary. If IncludePadding is true, it will be ensured + * that line width is a multiple of 4. padding bytes are included if necessary. + * + * NOTE: systems with big endian byte order may require masks in inversion order. + */ + + bool GetBits(void* Buffer, unsigned int &Size, unsigned int RedMask, unsigned int GreenMask, unsigned int BlueMask, unsigned int AlphaMask, bool IncludePadding = true) { + bool Result = false; + + uint32_t BitCountRed = CColor::BitCountByMask(RedMask); + uint32_t BitCountGreen = CColor::BitCountByMask(GreenMask); + uint32_t BitCountBlue = CColor::BitCountByMask(BlueMask); + uint32_t BitCountAlpha = CColor::BitCountByMask(AlphaMask); + + unsigned int BitCount = (BitCountRed + BitCountGreen + BitCountBlue + BitCountAlpha + 7) & ~7; + + if (BitCount > 32) { + return false; + } + + unsigned int w = GetWidth(); + //unsigned int LineWidth = (w + 3) & ~3; + unsigned int dataBytesPerLine = (w * BitCount + 7) / 8; + unsigned int LineWidth = (dataBytesPerLine + 3) & ~3; + + if (Size == 0 || Buffer == 0) { + //Size = (LineWidth * GetHeight() * BitCount) / 8 + sizeof(unsigned int); + Size = (GetWidth() * GetHeight() * BitCount) / 8 + sizeof(unsigned int); + return true; + } + + uint8_t* BufferPtr = (uint8_t*) Buffer; + + Result = true; + + uint32_t BitPosRed = CColor::BitPositionByMask(RedMask); + uint32_t BitPosGreen = CColor::BitPositionByMask(GreenMask); + uint32_t BitPosBlue = CColor::BitPositionByMask(BlueMask); + uint32_t BitPosAlpha = CColor::BitPositionByMask(AlphaMask); + + unsigned int j = 0; + + for (unsigned int i = 0; i < m_BitmapSize; i++) { + *(uint32_t*) BufferPtr = + (CColor::Convert(m_BitmapData[i].Blue, 8, BitCountBlue) << BitPosBlue) | + (CColor::Convert(m_BitmapData[i].Green, 8, BitCountGreen) << BitPosGreen) | + (CColor::Convert(m_BitmapData[i].Red, 8, BitCountRed) << BitPosRed) | + (CColor::Convert(m_BitmapData[i].Alpha, 8, BitCountAlpha) << BitPosAlpha); + + if (IncludePadding) { + j++; + if (j >= w) { + for (unsigned int k = 0; k < LineWidth - dataBytesPerLine; k++) { + BufferPtr += (BitCount >> 3); + } + j = 0; + } + } + + BufferPtr += (BitCount >> 3); + } + + Size -= sizeof(unsigned int); + + return Result; + } + + /* See GetBits(). + * It creates a corresponding color table (palette) which have to be destroyed by the user after usage. + * + * Supported Bit depths are: 4, 8 + * + * Todo: Optimize, use optimized palette, do ditehring (see my dithering class), support padding for 4 bit bitmaps + */ + + bool GetBitsWithPalette(void* Buffer, unsigned int &Size, unsigned int BitCount, BGRA* &Palette, unsigned int &PaletteSize, bool OptimalPalette = false, bool IncludePadding = true) { + bool Result = false; + + if (BitCount > 16) { + return false; + } + + unsigned int w = GetWidth(); + unsigned int dataBytesPerLine = (w * BitCount + 7) / 8; + unsigned int LineWidth = (dataBytesPerLine + 3) & ~3; + + if (Size == 0 || Buffer == 0) { + Size = (LineWidth * GetHeight() * BitCount) / 8; + return true; + } + + + if (OptimalPalette) { + PaletteSize = 0; + // Not implemented + } else { + if (BitCount == 1) { + PaletteSize = 2; + // Not implemented: Who need that? + } else if (BitCount == 4) { // 2:2:1 + PaletteSize = 16; + Palette = new BGRA[PaletteSize]; + for (int r = 0; r < 4; r++) { + for (int g = 0; g < 2; g++) { + for (int b = 0; b < 2; b++) { + Palette[r | g << 2 | b << 3].Red = r ? (r << 6) | 0x3f : 0; + Palette[r | g << 2 | b << 3].Green = g ? (g << 7) | 0x7f : 0; + Palette[r | g << 2 | b << 3].Blue = b ? (b << 7) | 0x7f : 0; + Palette[r | g << 2 | b << 3].Alpha = 0xff; + } + } + } + } else if (BitCount == 8) { // 3:3:2 + PaletteSize = 256; + Palette = new BGRA[PaletteSize]; + for (int r = 0; r < 8; r++) { + for (int g = 0; g < 8; g++) { + for (int b = 0; b < 4; b++) { + Palette[r | g << 3 | b << 6].Red = r ? (r << 5) | 0x1f : 0; + Palette[r | g << 3 | b << 6].Green = g ? (g << 5) | 0x1f : 0; + Palette[r | g << 3 | b << 6].Blue = b ? (b << 6) | 0x3f : 0; + Palette[r | g << 3 | b << 6].Alpha = 0xff; + } + } + } + } else if (BitCount == 16) { // 5:5:5 + // Not implemented + } + } + + unsigned int j = 0; + uint8_t* BufferPtr = (uint8_t*) Buffer; + + for (unsigned int i = 0; i < m_BitmapSize; i++) { + if (BitCount == 1) { + // Not implemented: Who needs that? + } else if (BitCount == 4) { + *BufferPtr = ((m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3) << 4; + i++; + *BufferPtr |= (m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3; + } else if (BitCount == 8) { + *BufferPtr = (m_BitmapData[i].Red >> 5) | (m_BitmapData[i].Green >> 5) << 3 | (m_BitmapData[i].Blue >> 5) << 6; + } else if (BitCount == 16) { + // Not implemented + } + + if (IncludePadding) { + j++; + if (j >= w) { + for (unsigned int k = 0; k < (LineWidth - dataBytesPerLine); k++) { + BufferPtr += BitCount / 8; + } + j = 0; + } + } + + BufferPtr++; + } + + Result = true; + + return Result; + } + + /* Set Bitmap Bits. Will be converted to RGBA internally */ + + bool SetBits(void* Buffer, unsigned int Width, unsigned int Height, unsigned int RedMask, unsigned int GreenMask, unsigned int BlueMask, unsigned int AlphaMask = 0) { + if (Buffer == 0) { + return false; + } + + uint8_t *BufferPtr = (uint8_t*) Buffer; + + Dispose(); + + m_BitmapHeader.Width = Width; + m_BitmapHeader.Height = Height; + m_BitmapHeader.BitCount = 32; + m_BitmapHeader.Compression = 3; + + m_BitmapSize = GetWidth() * GetHeight(); + m_BitmapData = new BGRA[m_BitmapSize]; + + /* Find bit count by masks (rounded to next 8 bit boundary) */ + + unsigned int BitCount = (CColor::BitCountByMask(RedMask | GreenMask | BlueMask | AlphaMask) + 7) & ~7; + + uint32_t BitCountRed = CColor::BitCountByMask(RedMask); + uint32_t BitCountGreen = CColor::BitCountByMask(GreenMask); + uint32_t BitCountBlue = CColor::BitCountByMask(BlueMask); + uint32_t BitCountAlpha = CColor::BitCountByMask(AlphaMask); + + for (unsigned int i = 0; i < m_BitmapSize; i++) { + unsigned int Color = 0; + if (BitCount <= 8) { + Color = *((uint8_t*) BufferPtr); + BufferPtr += 1; + } else if (BitCount <= 16) { + Color = *((uint16_t*) BufferPtr); + BufferPtr += 2; + } else if (BitCount <= 24) { + Color = *((uint32_t*) BufferPtr); + BufferPtr += 3; + } else if (BitCount <= 32) { + Color = *((uint32_t*) BufferPtr); + BufferPtr += 4; + } else { + /* unsupported */ + BufferPtr += 1; + } + m_BitmapData[i].Alpha = CColor::Convert(CColor::ComponentByMask(Color, AlphaMask), BitCountAlpha, 8); + m_BitmapData[i].Red = CColor::Convert(CColor::ComponentByMask(Color, RedMask), BitCountRed, 8); + m_BitmapData[i].Green = CColor::Convert(CColor::ComponentByMask(Color, GreenMask), BitCountGreen, 8); + m_BitmapData[i].Blue = CColor::Convert(CColor::ComponentByMask(Color, BlueMask), BitCountBlue, 8); + } + + return true; + } +}; + +#endif