BOOL WriteDIB( LPTSTR szFile, HANDLE hDIB)
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;
if (!hDIB)
return FALSE;
HANDLE file = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
lpbi = (LPBITMAPINFOHEADER)hDIB;
int nColors = 1 << lpbi->biBitCount;
// Fill in the fields of the file header
hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM"
hdr.bfSize = GlobalSize (hDIB) + sizeof( hdr );
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD) (sizeof( hdr ) + lpbi->biSize +
nColors * sizeof(RGBQUAD));
// Write the file header
DWORD numwritten;
WriteFile(file, &hdr, sizeof(hdr), &numwritten, NULL);
// Write the DIB header and the bits
DWORD numwrittentwo;
WriteFile(file, lpbi, GlobalSize(hDIB), &numwrittentwo, NULL);
CloseHandle(file);
return TRUE;
}
//// Here's where I call the function
BITMAPINFO info;
ZeroMemory( &info.bmiHeader, sizeof(BITMAPINFOHEADER) );
info.bmiHeader.biWidth=500; // Set size you need
info.bmiHeader.biHeight=500; // Set size you need
info.bmiHeader.biPlanes=1;
info.bmiHeader.biBitCount=24; // Can be 8, 16, 32 bpp or
// other number
info.bmiHeader.biSizeImage=0;
info.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
info.bmiHeader.biClrUsed= 0;
info.bmiHeader.biClrImportant= 0;
VOID *pvBits;
HDC tempdc = CreateCompatibleDC(hdc);
HBITMAP dib = CreateDIBSection(tempdc, &info, DIB_RGB_COLORS, &pvBits, NULL, 0);
SelectObject(tempdc, dib);
BitBlt(tempdc, 0, 0, 32, 32, bmpdc, 0, 0, SRCCOPY);
WriteDIB("out.bmp", dib);
?
Saving a Bitmap
Alright this topic has been covered, but i've searched and searched and haven't found a decent answer, or at least anything that's worked for me. I'm using some code that I snagged from CodeGuru here.
it crashes on the line "int nColors = 1 << lpbi->biBitCount;"
Anyway here's the full code im trying to use:
Hello,
You cannot treat a handle as a memory location. If hDib was a handle to some memory (allocated with GlobalAlloc()) you would have to call GlobalLock() (and GlobalUnlock() when you do not need it anymore) i.e. replacing
with
In your case, the hDib is not even a handle to some global memory. It is a GDI object - something completely different. It will be easier to direcly use you BITMAPINFO structure and your pvBits pointer. If you don't want to do this then you'll have to call GetDIBits() to get the needed informations in your WriteDIB() function - which is silly since you have these informations when you create your hDib.
HTH,
You cannot treat a handle as a memory location. If hDib was a handle to some memory (allocated with GlobalAlloc()) you would have to call GlobalLock() (and GlobalUnlock() when you do not need it anymore) i.e. replacing
lpbi = (LPBITMAPINFOHEADER)hDIB;
with
lpbi = (LPBITMAPINFOHEADER)(GlobalLock(hDIB));// ... do whatever you wantGlobalUnlock(hDIB);
In your case, the hDib is not even a handle to some global memory. It is a GDI object - something completely different. It will be easier to direcly use you BITMAPINFO structure and your pvBits pointer. If you don't want to do this then you'll have to call GetDIBits() to get the needed informations in your WriteDIB() function - which is silly since you have these informations when you create your hDib.
HTH,
Ok now i have
but it only seems to print the header, it's one line starting with BM and the file is like 1 kb, opens to default blank view in mspaint
BOOL WriteDIB( LPTSTR szFile, HBITMAP hbmp, HDC hdc, BITMAPINFO bmpi){ BITMAPFILEHEADER hdr; if (!hbmp) return FALSE; HANDLE file = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); int nColors = 1 << bmpi.bmiHeader.biBitCount; // Fill in the fields of the file header hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM" hdr.bfSize = GlobalSize (hbmp) + sizeof( hdr ); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = (DWORD) (sizeof( hdr ) + bmpi.bmiHeader.biSize + nColors * sizeof(RGBQUAD)); // Write the file header DWORD numwritten, numwrittentwo, numwrittenthree; WriteFile(file, &hdr, sizeof(hdr), &numwritten, NULL); // Write the DIB header and the bits WriteFile(file, &bmpi.bmiHeader, sizeof(bmpi.bmiHeader), &numwrittentwo, NULL); LPVOID *pvBits; GetDIBits(hdc, hbmp, 0, 32, pvBits, &bmpi, DIB_RGB_COLORS); WriteFile(file, pvBits, sizeof(pvBits), &numwrittenthree, NULL); CloseHandle(file); return TRUE;}
but it only seems to print the header, it's one line starting with BM and the file is like 1 kb, opens to default blank view in mspaint
You're writing sizeof( pvBits ) bytes to the file. As pvBits is a pointer you're writing only (in your case) 4 bytes.
You need to calculate the actual byte size of the image data. Don't forget to take the line padding in account!
You need to calculate the actual byte size of the image data. Don't forget to take the line padding in account!
so let's see, for a 32x32 bitmap, at 24 bit, (since right now i have info.bmiHeader.biSizeImage=0;) i should have info.bmiHeader.biSizeImage = (32*sizeof(RGBQUAD))*(32*sizeof(RGBQUAD))??
Quote:Original post by Funkymunky
so let's see, for a 32x32 bitmap, at 24 bit, (since right now i have info.bmiHeader.biSizeImage=0;) i should have info.bmiHeader.biSizeImage = (32*sizeof(RGBQUAD))*(32*sizeof(RGBQUAD))??
No.
The correct formula to compute the size of an Windows DIB is :
int linesize = ((info.bmiHeader.biWidth + 3) & (~3));info.bmiHeader.biSizeImage = linesize * info.bmiHeader.biHeight * info.bmiHeader.biBitCount / 8;
linesize is the smallest multiple of 4 which is equal or greater than width - the line padding Endurion just talked about. This is one of the funny thing about Windows DIB.
HTH,
Ok it's still only spitting out
BM□□□□□□□□6□□□(□□□ □□ □□□□□□□□□□□□
□□□□□□□□□□□□□□□□□□
in mspaint it's a 32 by 32 24 color plain white bitmap (bits dont get written?)
in paint shop pro it's a torn image, a bunch of static
*UPDATE*
ive changed WriteFile(file, pvBits, sizeof(pvBits), &numwrittenthree, NULL); to WriteFile(file, &pvBits, bmpi.bmiHeader.biSizeImage, &numwrittenthree, NULL);
now it spits out a 4k image, same results (white and torn) but now there's some garbage after those first two lines.
...help?
BM□□□□□□□□6□□□(□□□ □□ □□□□□□□□□□□□
□□□□□□□□□□□□□□□□□□
in mspaint it's a 32 by 32 24 color plain white bitmap (bits dont get written?)
in paint shop pro it's a torn image, a bunch of static
*UPDATE*
ive changed WriteFile(file, pvBits, sizeof(pvBits), &numwrittenthree, NULL); to WriteFile(file, &pvBits, bmpi.bmiHeader.biSizeImage, &numwrittenthree, NULL);
now it spits out a 4k image, same results (white and torn) but now there's some garbage after those first two lines.
...help?
Quote:Original post by Funkymunky
*UPDATE*
ive changed WriteFile(file, pvBits, sizeof(pvBits), &numwrittenthree, NULL); to WriteFile(file, &pvBits, bmpi.bmiHeader.biSizeImage, &numwrittenthree, NULL);
now it spits out a 4k image, same results (white and torn) but now there's some garbage after those first two lines.
...help?
&pvBits points tp pvBits, while pvBits points to your bits. You should use:
WriteFile(file, pvBits, bmpi.bmiHeader.biSizeImage, &numwrittenthree, NULL);<s>WriteFile(file, &pvBits, bmpi.bmiHeader.biSizeImage, &numwrittenthree, NULL);</s>
HTH,
Ok...
Let's do it again:
FIRST: I assume that you correctly computed bmpi.bmiHeader.biSizeImage before you entered in the function.
WRONG (1) : GetDIBits() won't allocate the memory for you. For some reason, your program do not crash - because the bitmap is small enough, probably, meaning that you are crashing your memory. You'll have to do:
Then you can call GetDIBits() as you called it. Don't forget to delete [] the memory.
WRONG (2) : sizeof(pvBits) is the size of the pointer - which is really sizeof(LPVOID) - on intel 32 architectures, it is equal to 4. You must use bmpi.bmiHeader.biSizeImage again here:
Let's do it again:
Quote:Original post by Funkymunky
Ok now i haveBOOL WriteDIB( LPTSTR szFile, HBITMAP hbmp, HDC hdc, BITMAPINFO bmpi){ BITMAPFILEHEADER hdr; if (!hbmp) return FALSE; HANDLE file = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); int nColors = 1 << bmpi.bmiHeader.biBitCount; // Fill in the fields of the file header hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM" hdr.bfSize = GlobalSize (hbmp) + sizeof( hdr ); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = (DWORD) (sizeof( hdr ) + bmpi.bmiHeader.biSize + nColors * sizeof(RGBQUAD)); // Write the file header DWORD numwritten, numwrittentwo, numwrittenthree; WriteFile(file, &hdr, sizeof(hdr), &numwritten, NULL); // Write the DIB header and the bits WriteFile(file, &bmpi.bmiHeader, sizeof(bmpi.bmiHeader), &numwrittentwo, NULL); LPVOID *pvBits; GetDIBits(hdc, hbmp, 0, 32, pvBits, &bmpi, DIB_RGB_COLORS); // WRONG (1) WriteFile(file, pvBits, sizeof(pvBits), &numwrittenthree, NULL); // WRONG (2) CloseHandle(file); return TRUE;}
but it only seems to print the header, it's one line starting with BM and the file is like 1 kb, opens to default blank view in mspaint
FIRST: I assume that you correctly computed bmpi.bmiHeader.biSizeImage before you entered in the function.
WRONG (1) : GetDIBits() won't allocate the memory for you. For some reason, your program do not crash - because the bitmap is small enough, probably, meaning that you are crashing your memory. You'll have to do:
pvBits = (LPVOID) new char[bmpi.bmiHeader.biSizeImage];
Then you can call GetDIBits() as you called it. Don't forget to delete [] the memory.
WRONG (2) : sizeof(pvBits) is the size of the pointer - which is really sizeof(LPVOID) - on intel 32 architectures, it is equal to 4. You must use bmpi.bmiHeader.biSizeImage again here:
WriteFile(file, pvBits, bmpi.bmiHeader.biSizeImage, &numwrittenthree, NULL);
LAST: as I already said, since you are creating your hBitmap right before calling the function, you might as well do:
BOOL WriteDIB(LPCTSTR szFileName, LPBITMAPINFO pBm, LPVOID pBits){ HFILE hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // make sure pBm->bmiHeader.biSizeImage is computed int ls = (pBm->bmiHeader.biWidth + 3) & (~3); pBm->bmiHeader.biSizeImage = ls * pBm->bmiHeader.biHeight * pBm->bmiHeader.biBitCount / 8; // if we are writing a 8 bit bitmap we must remember of the palette // - 256 RGBQUAD that are stored after pBm->bmiHeader. We are not handling // them in this code BITMAPFILEHEADER hdr; hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM" hdr.bfSize = sizeof(hdr) + sizeof(BITMAPINFOHEADER); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = hdr.bfSize; DWORD dwByteCount; WriteFile(hFile, &hdr, sizeof(hdr), &dwByteCount, NULL); WriteFile(hFile, pBm, pBm->bmiheader.biSize, &dwByteCount, NULL); WriteFile(hFile, pBits, pBm->bmiheader.biSizeImage, &dwByteCount, NULL); CloseHandle(hFile); return TRUE;}
You'll want to add the error handling code.
HTH,
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement