Hey guys,
I've been reading up on working with bitmaps and getting a good feel for it.
Using the Win32 API, I can create a bitmap, load a bitmap from file and I can even save to file a previously loaded bitmap.
Unfortunately, I am unable to save to file a bitmap which I create in memory. Now, I have searched and read thru the archives here and have not yet found the solution.
Below is my code for creating a bitmap, which I bitblt to my double-buffer and display on my main screen. This works great.
It creates a 150 X 100 pixel rectangle with an ellipse drawn in the center of it.
Code:
void MakeBitmap(HWND hwnd)
{
char bmpFile[BUFSIZE];
int bpp = 1;
SIZE SBitmap = {150, 100};
HDC hDC = HdcBuffer; // handle to double buffer
HBITMAP hBmp, hBmpOld;
HDC hMemDC;
COLORREF clrZeros, clrOnes;
PBITMAPINFO pbmpi;
hBmp = CreateBitmap(SBitmap.cx, SBitmap.cy, 1, bpp, NULL);
hMemDC = CreateCompatibleDC(hDC);
hBmpOld = (HBITMAP) SelectObject(hMemDC, hBmp);
clrZeros = PALETTERGB(0,0,255);
SetTextColor(hDC, clrZeros);
PatBlt(hMemDC, 0, 0, SBitmap.cx, SBitmap.cy, BLACKNESS);
clrOnes = PALETTERGB(255,0,0);
SetBkColor(hDC, clrOnes);
Ellipse(hMemDC, 0, 0, SBitmap.cx, SBitmap.cy);
BitBlt(hDC, 10, 10, SBitmap.cx, SBitmap.cy, hMemDC, 0, 0, SRCCOPY);
InvalidateRect(hwnd, &glrect, FALSE);
UpdateWindow(hwnd);
//..............HERE: is the BITMAP save to file section:
strcpy(bmpFile, "test.bmp");
pbmpi = CreateBitmapInfoStruct(hwnd, hBmp);
CreateBMPFile(hwnd, bmpFile, pbmpi, hBmp, hMemDC);
//......................................................
DeleteObject(SelectObject(hMemDC, hBmpOld));
DeleteDC(hMemDC);
DeleteDC(hBmp);
ReleaseDC(hwnd, hDC);
}
Near the bottom, I call two functions taken from the SDK (Storing an Image) which does not seem to work in this case.
Here is the code for Storing an Image:
Code:
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;
// Retrieve the bitmap color format, width, and height.
if(!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
{
printf("error:GetObject\n");
exit(0);
}
// Convert the color format to a count of bits.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
if(cClrBits == 1)
{
cClrBits = 1;
}
else if(cClrBits <= 4)
{
cClrBits = 4;
}
else if(cClrBits <= 8)
{
cClrBits = 8;
}
else if(cClrBits <= 16)
{
cClrBits = 16;
}
else if(cClrBits <= 24)
{
cClrBits = 24;
}
else
{
cClrBits = 32;
}
if(cClrBits != 24)
{
pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits));
}
else
{
pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
if(cClrBits < 24)
{
pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
}
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight;
pbmi->bmiHeader.biClrImportant = 0;
return pbmi;
}
Code:
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
{
HANDLE hf; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
LPBYTE lpBits; // memory pointer
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
BYTE *hp; // byte pointer
DWORD dwTmp;
pbih = (PBITMAPINFOHEADER) pbi;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
if(!lpBits)
{
printf("error:GlobalAlloc\n");
exit(0);
}
if(!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, DIB_RGB_COLORS))
{
printf("error:GetDIBits\n");
exit(0);
}
hf = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
if(hf == INVALID_HANDLE_VALUE)
{
printf("error:CreateFile\n");
exit(0);
}
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
if(!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL))
{
printf("error:WriteFile-1\n");
exit(0);
}
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
if(!WriteFile(hf, (LPVOID) pbih, (sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof(RGBQUAD)), (LPDWORD) &dwTmp, NULL))
{
printf("error:WriteFile-2\n");
exit(0);
}
// Copy the array of color indices into the .BMP file.
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
if(!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
{
printf("error:WriteFile-3\n");
exit(0);
}
if(!CloseHandle(hf))
{
printf("error:CloseHandle\n");
exit(0);
}
GlobalFree((HGLOBAL)lpBits);
}
*Re: the printf statements: I use a console window for error messages.
The Storing an Image code works when I load an image from a disk-file, so I know it does work. Just not when I create the bitmap in memory.
What I end up with is a BLACK rectangle saved to file, instead of my bitmap.
I have read of this exact same problem in the archives. However, I cannot figure out a solution.
Any ideas ?
Am I missing something obvious ?