void msg(const int x, const char* message = NULL);
void CPowerNetworkCaptureView::OnFileSaveBitmap()
{
// grab the device context and get it's dimensions
CClientDC ClientDC(this);
OnPrepareDC (&ClientDC);
OnDraw(&ClientDC);
CSize ClientSize = ClientDC.GetWindowExt();
DWORD width = ClientSize.cx;
DWORD height = ClientSize.cy;
DWORD pitch = width * 3;
// set up some bitmap information
WORD fileID = ((WORD) ('M' << 8) | 'B');
DWORD fileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (height * pitch);
WORD infoBPP = 24;
// initialize bmfHeader and bmiHeader structures
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bmiHeader;
memset(&bmfHeader, 0, sizeof(BITMAPFILEHEADER));
memset(&bmiHeader, 0, sizeof(BITMAPINFOHEADER));
bmfHeader.bfType = fileID;
bmfHeader.bfSize = fileSize;
bmfHeader.bfOffBits = 54;
bmiHeader.biSize = 40;
bmiHeader.biWidth = width;
bmiHeader.biHeight = height;
bmiHeader.biBitCount = infoBPP;
// get pixel data from the DC
COLORREF color; // stored as 0x00bbggrr
BYTE (*pixels)[3] = new BYTE[width*height][3];
int i=0;
for (int j=height-1; j>=0; j--) {
for (int k=0; k<width; k++)
{
BYTE* pixel = pixels[i*pitch + k];
color = ClientDC.GetPixel(k, j);
*pixel++ = ((BYTE) (color >> 16) & 0xff);
*pixel++ = ((BYTE) (color >> 8) & 0xff);
*pixel = ((BYTE) color & 0xff);
}
i++;
}
// write the bitmap to a file
DWORD dwWritten;
HANDLE fh;
LPSTR lpFileName = "c:\\test.bmp";
fh = CreateFile(lpFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (fh == INVALID_HANDLE_VALUE)
{
MessageBox("Unable to create bitmap file.", "Error!", MB_ICONERROR);
return;
}
WriteFile(fh, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
WriteFile(fh, (LPSTR)&bmiHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
WriteFile(fh, pixels, width * pitch, &dwWritten, NULL);
CloseHandle(fh);
// memory cleanup
delete [] pixels;
pixels = 0;
}
MFC, DC and Bitmap question...
I am trying to save the contents of an SDI document window to a .bmp file. I know nothing about MFC, so this is just what I figured should work (and I'm sure I'm wrong). I've created a menu item called to save the bitmap and I've added a function for it in the CView class of my application. I don't know if this is the right class to put it in or not. Also, I'm not sure if I am getting the right DC. I have found that the GetPixel calls always return -1 and that leads me to believe that I am using the wrong DC. Can someone tell me what is wrong with this code or if there is a more simple way to do this? The j loop goes through about 315 iterations and then the program crashes. If I try to break out of the loop at that time, the third call to WriteFile fails. In case you need to know, the width and height are usually 1260 and 945 respectively. I really don't have a clue how to do what I want to do and this was the best that I could come up with. Thanks so much for your help.
[edited by - matthew02 on April 21, 2002 1:39:48 AM]
Can''t you just use SelectObject to retrieve the current bitmap in the DC, then GetObject to get BITMAP for it, and use the bitmap bits in that struct instead of reading the bitmap pixel-by-pixel?
I can''t be bothered to see what''s wrong with the posted code at this moment.
I can''t be bothered to see what''s wrong with the posted code at this moment.
---visit #directxdev on afternet <- not just for directx, despite the name
Thanks for your suggestion. The problem is, I really don''t know how to use SelectObject and GetObject. I don''t know anything about MFC and the help files aren''t doing their job for me. The Win32 counterparts aren''t helping me either. I''ve tried what you recommended, but I''m not really sure that I''m doing it correctly. If you have time later, maybe you could take a look at what I came up with. Thanks.
void CPowerNetworkCaptureView::OnFileSaveBitmap() { // grab the device context and get it''s dimensions CClientDC ClientDC(this); OnPrepareDC(&ClientDC); OnDraw(&ClientDC); CSize ClientSize = ClientDC.GetWindowExt(); CBitmap ClientBitmap; ClientBitmap.CreateCompatibleBitmap(&ClientDC, ClientSize.cx, ClientSize.cy); ClientDC.SelectObject(&ClientBitmap); BITMAP bitmap; ClientBitmap.GetObject(sizeof(BITMAP), (LPVOID) &bitmap); DWORD width = bitmap.bmWidth;; DWORD height = bitmap.bmHeight; DWORD pitch = bitmap.bmWidthBytes; // size of one scan line (stride) WORD bpp = bitmap.bmBitsPixel; // set up some bitmap information WORD fileID = ((WORD) (''M'' << 8) | ''B''); DWORD fileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (height * pitch); // initialize bmfHeader and bmiHeader structures BITMAPFILEHEADER bmfHeader; BITMAPINFOHEADER bmiHeader; memset(&bmfHeader, 0, sizeof(BITMAPFILEHEADER)); memset(&bmiHeader, 0, sizeof(BITMAPINFOHEADER)); bmfHeader.bfType = fileID; bmfHeader.bfSize = fileSize; bmfHeader.bfOffBits = 54; bmiHeader.biSize = 40; bmiHeader.biWidth = width; bmiHeader.biHeight = height; bmiHeader.biBitCount = bpp; // write the bitmap to a file DWORD dwWritten; HANDLE fh; LPSTR lpFileName = "c:\\test.bmp"; fh = CreateFile(lpFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL); if (fh == INVALID_HANDLE_VALUE) { MessageBox("Unable to create bitmap file.", "Error!", MB_ICONERROR); return; } WriteFile(fh, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); WriteFile(fh, (LPSTR)&bmiHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL); WriteFile(fh, bitmap.bmBits, height * pitch, &dwWritten, NULL); CloseHandle(fh);}
SelectObject (the Win32 version, not MFC one) returns the old object. You need to use GetObject on that bitmap, not on the bitmap you just created.
May I also suggest you use windowsx.h and replace SelectObject with SelectBitmap and so on? Look into that header to see what it does for you.
May I also suggest you use windowsx.h and replace SelectObject with SelectBitmap and so on? Look into that header to see what it does for you.
---visit #directxdev on afternet <- not just for directx, despite the name
I am still having problems. I've looked through windowsx.h, but I don't know what functions to use or how to use them to get what I want. My call to GetObject() always fails and GetLastError() returns 0 for the error code. I've posted the relevant code below. Could you take a look at it and see if I am doing the right thing? Thanks.
[edited by - matthew02 on April 21, 2002 1:38:38 PM]
void msg(const int x, const char* message = NULL);void CPowerNetworkCaptureView::OnFileSaveBitmap() { // grab the device context and get it's dimensions CClientDC ClientDC(this); OnPrepareDC(&ClientDC); OnDraw(&ClientDC); BITMAP bitmap; HGDIOBJ hGdiObj = SelectObject(ClientDC.GetSafeHdc(), NULL); if (!GetObject(hGdiObj, sizeof(BITMAP), (LPVOID) &bitmap)) { DWORD dwError = GetLastError(); msg(dwError, "Error!"); return; } ...}
[edited by - matthew02 on April 21, 2002 1:38:38 PM]
Is hGdiObj NULL? If yes, create and select a compatible bitmap like you did earlier just to keep Windows happy.
---visit #directxdev on afternet <- not just for directx, despite the name
hGdiObj is NULL, but even when I create a compatible bitmap, it remains NULL. hBitmap is not NULL, so I''m not sure exactly what the problem is. Thanks.
void msg(const int x, const char* message = NULL);void CPowerNetworkCaptureView::OnFileSaveBitmap() { // grab the device context and get it''s dimensions CClientDC ClientDC(this); OnPrepareDC(&ClientDC); OnDraw(&ClientDC); CSize ClientSize = ClientDC.GetWindowExt(); HBITMAP hBitmap = CreateCompatibleBitmap(ClientDC.GetSafeHdc(), ClientSize.cx, ClientSize.cy);msg(hBitmap == NULL, "hBitmap == NULL"); HGDIOBJ hGdiObj = SelectObject(ClientDC.GetSafeHdc(), hBitmap);msg(hGdiObj == NULL, "hGdiObj == NULL"); BITMAP bitmap; if (!GetObject(hGdiObj, sizeof(BITMAP), (LPVOID) &bitmap)) { DWORD dwError = GetLastError(); msg(dwError, "Error!"); return; }
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement