/*
* 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>
#include <vector>
#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;
std::vector<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_BitmapSize(0) {
Dispose();
}
CBitmap(const char* Filename) : m_BitmapSize(0) {
Load(Filename);
}
~CBitmap() {
Dispose();
}
void Dispose() {
memset(&m_BitmapFileHeader, 0, sizeof(m_BitmapFileHeader));
memset(&m_BitmapHeader, 0, sizeof(m_BitmapHeader));
}
/* Load specified Bitmap and stores it as BGRA 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
std::vector<BGRA> ColorTable(ColorTableSize); // std::bad_alloc exception should be thrown if memory is not available
file.read((char*) ColorTable.data(), sizeof(BGRA) * m_BitmapHeader.ClrUsed);
/* ... Color Table for 16 bits images are not supported yet */
m_BitmapSize = GetWidth() * GetHeight();
m_BitmapData.resize(m_BitmapSize);
unsigned int LineWidth = ((GetWidth() * GetBitCount() / 8) + 3) & ~3;
std::vector<uint8_t> Line(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.data(), LineWidth);
uint8_t *LinePtr = Line.data();
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 && j < GetWidth(); k++, j++) {
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++;
} 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++;
if (++j >= GetWidth())
break;
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++;
} 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.data(), LineWidth);
uint8_t *LinePtr = Line.data();
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++;
}
}
}
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);
unsigned int LineWidth = (GetWidth() * BitCount / 8 + 3) & ~3;
//bfh.Size = (GetWidth() * GetHeight() * BitCount) / 8 + bfh.BitsOffset;
bfh.Size = LineWidth * GetHeight() + 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;
bh.Compression = 0; // BGRA
//bh.AlphaMask = 0xff000000;
//bh.BlueMask = 0x000000ff;
//bh.GreenMask = 0x0000ff00;
//bh.RedMask = 0x00ff0000;
} 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
}
bh.Planes = 1;
bh.Height = GetHeight();
bh.Width = GetWidth();
bh.SizeImage = (LineWidth * GetHeight());
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.data(), bh.SizeImage);
} else if (BitCount < 16) {
bh.SizeImage = 0;
std::vector<BGRA> Palette;
unsigned int PaletteSize = 0;
if (GetBitsWithPalette(nullptr, bh.SizeImage, BitCount, Palette, PaletteSize)) {
std::vector<uint8_t> Bitmap((size_t)bh.SizeImage);
if (GetBitsWithPalette(Bitmap.data(), bh.SizeImage, BitCount, Palette, PaletteSize)) {
bh.ClrUsed = PaletteSize;
bfh.BitsOffset += PaletteSize * sizeof(BGRA);
bfh.Size = bh.SizeImage + bfh.BitsOffset;
file.write((char*)&bfh, BITMAP_FILEHEADER_SIZE);
file.write((char*)&bh, sizeof(BITMAP_HEADER));
file.write((char*)Palette.data(), PaletteSize * sizeof(BGRA));
file.write((char*)Bitmap.data(), bh.SizeImage);
}
}
} 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)) {
std::vector<char> Bitmap( (size_t)bh.SizeImage );// = new uint8_t[bh.SizeImage];
if (GetBits(Bitmap.data(), bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
file.write((char*)&bfh, sizeof(BITMAP_FILEHEADER));
file.write((char*)&bh, sizeof(BITMAP_HEADER));
file.write((char*) Bitmap.data(), 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;
}
unsigned int GetPixelsStride() {
return GetWidth();
}
unsigned int GetBytesStride() {
return GetWidth() * sizeof(BGRA);
}
/* 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(BGRA);
Result = m_BitmapSize != 0;
}
else if (Size < m_BitmapSize * sizeof(BGRA)) {
Result = false;
}
else {
memcpy(Buffer, m_BitmapData.data(), Size);
Result = true;
}
return Result;
}
/* Returns internal BGRA buffer */
void* GetBits() {
return m_BitmapData.data();
}
BGRA* GetBGRA() {
return m_BitmapData.data();
}
/* 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);
Size = LineWidth * GetHeight() + sizeof(unsigned int);
return true;
}
uint8_t* BufferPtr = (uint8_t*) Buffer;
uint8_t* LinePtr = (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);
BufferPtr += (BitCount >> 3);
if (IncludePadding) {
j++;
if (j >= w) {
//for (unsigned int k = 0; k < LineWidth - dataBytesPerLine; k++) {
// BufferPtr += (BitCount >> 3);
//}
LinePtr += LineWidth;
BufferPtr = LinePtr;
j = 0;
}
}
}
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, std::vector<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);
return true;
}
if (Size <(LineWidth * GetHeight() * BitCount)) {
return false;
}
if (OptimalPalette) {
PaletteSize = 0;
// Not implemented
return false;
} else {
if (BitCount == 1) {
PaletteSize = 2;
// Not implemented: Who need that?
return false;
} else if (BitCount == 4) { // 2:2:1
PaletteSize = 16;
Palette.resize(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.resize(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;
unsigned int ww = 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;
if (++ww < w) {
j++;
if (++i < m_BitmapSize) {
*BufferPtr |= (m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3;
++ww;
}
}
ww %= w;
} 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;
//}
BufferPtr += LineWidth - dataBytesPerLine;
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.resize(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