I have a field device that uses the raster bytes from a bitmap to display an 8 Bit-per-pixel image. The device uses its own color table to display bitmaps which were created in MS Paint.
Given that the field device does not store the original color table, is it possible to download the image bytes, and recreate the bitmap in Windows? The bpp, height and width are all known, just the color table itself is missing. MS Paint seems to use the same color indexes for 256 bitmaps, so it seems that this should be possible.
I have a bitmap tools class, and I can create a 24-bit bitmap using the function shown below, and I am trying to modify this to also create 256 (8 bpp) bitmaps. What would it take to make this work?
// This function needs to be fixed.
// It only works for 24-BPP bitmaps.
void BitmapTools::SetHbitmap (BYTE* pBitmapBits, LONG lWidth,LONG lHeight, WORD wBitsPerPixel)
{
if (wBitsPerPixel < 24)
{
MessageBox (GetFrame()->m_hWnd,
"Error at BitmapTools::SetHbitmap(). This function only works with 24 BPP bitmaps.",
"Error", MB_ICONERROR);
return;
}
// Some basic bitmap parameters
unsigned long headers_size = sizeof( BITMAPFILEHEADER ) +
sizeof( BITMAPINFOHEADER );
unsigned long pixel_data_size = lHeight * ( ( lWidth * ( wBitsPerPixel / 8 ) ) );
BITMAPINFOHEADER bmpInfoHeader = {0};
// Set the size
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
// Bit count
bmpInfoHeader.biBitCount = wBitsPerPixel;
// Use all colors
bmpInfoHeader.biClrImportant = 0;
// Use as many colors according to bits per pixel
if (wBitsPerPixel < 24)
{
bmpInfoHeader.biClrUsed = (1<<wBitsPerPixel);
}
else
{
bmpInfoHeader.biClrUsed = 0;
}
// Store as un Compressed
bmpInfoHeader.biCompression = BI_RGB;
// Set the height in pixels
bmpInfoHeader.biHeight = lHeight;
// Width of the Image in pixels
bmpInfoHeader.biWidth = lWidth;
// Default number of planes
bmpInfoHeader.biPlanes = 1;
// Calculate the image size in bytes
bmpInfoHeader.biSizeImage = pixel_data_size;
BITMAPFILEHEADER bfh = {0};
bfh.bfType = 0x4D42;
// Offset to the RGBQUAD
bfh.bfOffBits = headers_size;
// Total size of image including size of headers
bfh.bfSize = headers_size + pixel_data_size;
HDC hdc = ::GetDC(NULL);
UINT usage;
// This does not work. Is there a way to add an arbitrary color
// table containing all 256 colors?
if (wBitsPerPixel < 24)
{
usage = DIB_PAL_COLORS;
}
else
{
usage = DIB_RGB_COLORS;
}
//usage = DIB_RGB_COLORS;
this->H_Bitmap = CreateDIBitmap (hdc, &bmpInfoHeader, CBM_INIT, pBitmapBits,(BITMAPINFO*)&bmpInfoHeader, usage);
}
Edit: I made a new function based on someone else's post to create a 256 color bitmap, and I added the values from the color table used by MS Paint. It almost works, except the bottom-right of the image has a row of black pixels. Here is the code I am now using:
HBITMAP BitmapTools::Create8bppBitmap(HDC hdc, int width, int height, LPVOID pBits)
{
BITMAPINFO *bmi = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
BITMAPINFOHEADER &bih(bmi->bmiHeader);
bih.biSize = sizeof (BITMAPINFOHEADER);
bih.biWidth = width;
bih.biHeight = -height;
bih.biPlanes = 1;
bih.biBitCount = 8;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
//bih.biXPelsPerMeter = 14173;
//bih.biYPelsPerMeter = 14173;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
BYTE red[256] = {0, 128, 0, 128, 0, 128, 0, 192, 192, 166, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96,
128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32,
64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224,
0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192,
224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160,
192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128,
160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96,
128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64,
96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32,
64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0,
32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 255, 160,
128, 255, 0, 255, 0, 255, 0, 255};
BYTE green[256] = {0, 0, 128, 128, 0, 0, 128, 192, 220, 202, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64,
64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160,
160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 0,
0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 96, 96, 96, 96, 96,
96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 192, 192, 192,
192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32,
32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128,
128, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224,
224, 224, 224, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64,
64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160,
160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 251, 160, 128, 0, 255, 255, 0, 0, 255, 255};
BYTE blue[256] = {0, 0, 0, 0, 128, 128, 128, 192, 192, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 240, 164, 128, 0, 0, 0, 255, 255, 255, 255};
for (int i = 0; i <= 255; i++)
{
bmi->bmiColors[i].rgbBlue = blue[i];
bmi->bmiColors[i].rgbGreen = green[i];
bmi->bmiColors[i].rgbRed = red[i];
bmi->bmiColors[i].rgbReserved = 0;
}
void *Pixels = NULL;
HBITMAP hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &Pixels, NULL, 0);
//HBITMAP hbmp = CreateDIBSection(hdc, bmi, DIB_PAL_COLORS, &Pixels, NULL, 0);
if(pBits != NULL)
{
//fill the bitmap
BYTE* pbBits = (BYTE*)pBits;
BYTE *Pix = (BYTE *)Pixels;
memcpy(Pix, pbBits, width * height);
}
free(bmi);
return hbmp;
}
I use this function to save the bitmap:
BOOL BitmapTools::SaveHBitmap(const char* filename, HBITMAP hbitmap)
{
BITMAP bitmap;
if (!GetObjectW(hbitmap, sizeof(BITMAP), (void*)&bitmap))
return FALSE;
// Convert the color format to a count of bits.
WORD clrbits = (WORD)(bitmap.bmPlanes * bitmap.bmBitsPixel);
if (clrbits == 1) clrbits = 1;
else if (clrbits <= 4) clrbits = 4;
else if (clrbits <= 8) clrbits = 8;
else if (clrbits <= 16) clrbits = 16;
else if (clrbits <= 24) clrbits = 24;
else clrbits = 32;
//clrUsed is zero for 24 bit and higher
int clrUsed = (clrbits <= 8) ? (1 << clrbits) : 0;
//TRACE("clrUsed %dn", clrUsed);
int bitmapInfoSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * clrUsed;
PBITMAPINFO bitmapInfo = (PBITMAPINFO)new char[bitmapInfoSize];
memset(bitmapInfo, 0, bitmapInfoSize);
// Initialize the fields in the BITMAPINFO structure.
bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo->bmiHeader.biWidth = bitmap.bmWidth;
bitmapInfo->bmiHeader.biHeight = bitmap.bmHeight;
bitmapInfo->bmiHeader.biPlanes = bitmap.bmPlanes;
bitmapInfo->bmiHeader.biBitCount = bitmap.bmBitsPixel;
bitmapInfo->bmiHeader.biClrUsed = clrUsed;
bitmapInfo->bmiHeader.biCompression = BI_RGB;
// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// The width must be DWORD aligned unless the bitmap
// is RLE compressed.
int dibSize = ((bitmap.bmWidth * clrbits + 31) & ~31) / 8 * bitmap.bmHeight;
char* dib = new char[dibSize];
bitmapInfo->bmiHeader.biSizeImage = dibSize;
// Set biClrImportant to 0, indicating that all of
// the device colors are important.
bitmapInfo->bmiHeader.biClrImportant = 0;
//bitmapInfo->bmiColors [0].rgbBlue
PBITMAPINFOHEADER bmpInfoHeader = (PBITMAPINFOHEADER)bitmapInfo;
HDC hdc = CreateCompatibleDC(0);
if (!GetDIBits(hdc, hbitmap, 0, bmpInfoHeader->biHeight, dib, bitmapInfo, 0))
{
delete bitmapInfo;
delete[]dib;
return FALSE;
}
DWORD dwTmp;
BITMAPFILEHEADER bmpFileHeader;
bmpFileHeader.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + clrUsed * sizeof(RGBQUAD);
bmpFileHeader.bfSize = bmpFileHeader.bfOffBits + dibSize;
HANDLE hfile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile != INVALID_HANDLE_VALUE)
{
WriteFile(hfile,(LPVOID)&bmpFileHeader, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL);
WriteFile(hfile, (void*)bmpInfoHeader, sizeof(BITMAPINFOHEADER) + clrUsed * sizeof(RGBQUAD), (LPDWORD) &dwTmp, NULL);
WriteFile(hfile, (void*)dib, dibSize, (LPDWORD) &dwTmp, NULL);
CloseHandle(hfile);
}
DeleteDC(hdc);
delete bitmapInfo;
delete[]dib;
return TRUE;
}
Here is the image I get. Note the last row has a set of black pixels. I'm not 100% sure that the problem is with these functions (my next step will be to compare the bytes from the original bitmap to the ones from the field device).
Aucun commentaire:
Enregistrer un commentaire