The procedure is as follows. Create a memory device context, create and
select a bitmap into it. BitBlt the contents of my window's device context
into the memory device context. Then conver the bitmap into a DIB.
My question is are there any steps I can take in creating the original
window (from which I want to copy contents) or the memory device context
and/or bitmap in order to make the translation faster?
My code follows:
/*--------------------------------------------------------------------------
--------------*/
// Convert an HBTIMAP to a DIB
void * BMPToDIB(HDC hDC, HBITMAP hBitmap, int nWidth, int nHeight)
{
// check if bitmap handle is valid
if (!hBitmap)
return NULL;
BITMAPINFO bi;
::memset(&bi,0,sizeof(BITMAPINFO));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = nWidth;
bi.bmiHeader.biHeight = nHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 24;
bi.bmiHeader.biCompression = BI_RGB;
// call GetDIBits with a NULL lpBits param, so it will calculate the
// biSizeImage fi
eld for us
GetDIBits(hDC, hBitmap, 0, (UINT) bi.bmiHeader.biHeight, NULL, &bi,
DIB_RGB_COLORS);
// if the driver did not fill in the biSizeImage field, make one up
if (bi.bmiHeader.biSizeImage == 0)
bi.bmiHeader.biSizeImage = WIDTHBYTES((DWORD) nWidth * 3) * nHeight;
// get a buffer big enough to store everything
unsigned long nBuffSize = sizeof(BITMAPINFOHEADER) +
bi.bmiHeader.biSizeImage;
char * p = new char[nBuffSize];
// pointer to where bits start
char * pBits = p + sizeof(BITMAPINFOHEADER);
// call GetDIBits with a NON-NULL lpBits param, and actualy get the
// bits this time
if (GetDI
Bits(hDC, hBitmap, 0, (UINT) bi.bmiHeader.biHeight, pBits, &bi,
DIB_RGB_COLORS) == 0)
{
// clean up and return NULL
delete p;
return 0;
}
// copy the header onto the block of memory
::memcpy(p,&bi.bmiHeader,sizeof(BITMAPINFOHEADER));
// return handle to the DIB
return p;
}
/*--------------------------------------------------------------------------
--------------*/
// Write contents of view to bitmap
void CChildView::OnConvertToDIB()
{
HDC hDC = GetDC()->GetSafeHdc();
HDC hMemDC = ::CreateCompatibleDC(hDC);
if (hMemDC != NULL)
{
CRect rect;
GetClientRect(&rect);
HBITMAP hBMP = ::CreateCompatibleBitmap(hDC, rect.Width(),
rect.Height());
HGDIOBJ hOldObj = ::SelectObject(hMemDC, hBMP);
BOOL bSuccess = ::BitBlt(hMemDC, 0, 0, rect.Width(),
rect.Height(), hDC, 0, 0, SRCCOPY);
void * p = BMPToDIB(hMemDC,hBMP,rect.Width(),rect.Height());
// do some stuff with DIB
delete p;
::SelectObject(hDC, hOldObj);
::DeleteObject(hBMP);
::DeleteDC(hMemDC);
}
}
}
Actually, I think CreateDIBSection should be discussed more on this list - I
cringe everytime I see GetPixel and SetPixel calls in some of the
examples...
- jack
Samar Abbas Lotia <sal...@nquire.mail.com> wrote in message
news:erTkyck4$GA.2080@cpmsftngp03...
According to MSDN, it will return a pointer to some(???) bitmap bits. I
tried it, I got a non-NULL return yet the pointer I supplied is still NULL.
Very weird. Also, according to MSDN, I should supply a (void *) while VC++
6.0 SP4 is asking for a (void **). MSDN needs an update and a new set of GDI
functions wouldn't hurt either.
I declared the pointer as
unsigned char **BitsRGB=0;
This is a MFC CDialog based app, so I got the HDC like this
HWND hWnd=GetSafeHwnd();
HDC hdc=::GetDC(hWnd);
BITMAPINFO BitmapInfo;
unsigned char **BitsRGB=0;
BitmapInfo.bmiColors[0].rgbRed=0;
BitmapInfo.bmiColors[0].rgbGreen=0;
BitmapInfo.bmiColors[0].rgbBlue=0;
BitmapInfo.bmiColors[0].rgbReserved=0;
BitmapInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biWidth=(DWORD)Width;
BitmapInfo.bmiHeader.biHeight=(DWORD)Height;
BitmapInfo.bmiHeader.biPlanes=1;
BitmapInfo.bmiHeader.biBitCount=24;
BitmapInfo.bmiHeader.biCompression=BI_RGB;
BitmapInfo.bmiHeader.biSizeImage=BitmapInfo.bmiHeader.biWidth*abs(BitmapInfo
.bmiHeader.biHeight)*3;
BitmapInfo.bmiHeader.biClrImportant=0;
BitmapInfo.bmiHeader.biClrUsed=0;
BitmapInfo.bmiHeader.biXPelsPerMeter=0;
BitmapInfo.bmiHeader.biYPelsPerMeter=0;
//pColorData=0;
HBITMAP hBitmap=CreateDIBSection(hdc, &BitmapInfo, DIB_RGB_COLORS, (void
**)BitsRGB, NULL, 0);
It succeeds with a non-NULL hBitmap but BitsRGB is still 0.
All I want to do is get the pixel data of my client area, and save it as a
BMP. Any *simple* ideas?
V-man
Jack Thornton wrote in message <#wAp5C56$GA.279@cppssbbsa04>...
>I declared the pointer as
>unsigned char **BitsRGB=0;
[...]
> HBITMAP hBitmap=CreateDIBSection(hdc, &BitmapInfo, DIB_RGB_COLORS, (void
>**)BitsRGB, NULL, 0);
You seem to be confused about pointers. Try
unsigned char *BitsRGB=0;
HBITMAP hBitmap=CreateDIBSection(hdc, &BitmapInfo, DIB_RGB_COLORS, (void
**)&BitsRGB, NULL, 0);
Note the &
--
Graham Jones, author of SharpEye Music Reader
Windows version: http://www.visiv.co.uk
RISC OS version: http://www.balnakeil.demon.co.uk
21e Balnakeil, Durness, Lairg, Sutherland IV27 4PT, Scotland, UK
Basically,I have this
HDC hdc=::GetDC(hWnd);
BITMAPINFO BitmapInfo; <---some code to fill this up manually
unsigned char *BitsRGB=0;
HBITMAP hBitmap=CreateDIBSection(hdc, &BitmapInfo, DIB_RGB_COLORS, (void
**)&BitsRGB, NULL, 0);
BitsRGB is pointing to a valid address, but it's all BLACKNESS. Isn't this
thing suppose to create a bitmap associated with the HDC and already filled
with my window screen pixels?
Side note: maybe I should change that to BitsBGR :)
V-man
Graham Jones wrote in message ...
>In article <eQHmy8L#$GA.195@cppssbbsa04>, V-man <j_ca...@excie.com>
>writes
>
>>I declared the pointer as
>>unsigned char **BitsRGB=0;
>[...]
>> HBITMAP hBitmap=CreateDIBSection(hdc, &BitmapInfo, DIB_RGB_COLORS, (void
>>**)BitsRGB, NULL, 0);
>
>You seem to be confused about pointers. Try
>
>unsigned char *BitsRGB=0;
>
>HBITMAP hBitmap=CreateDIBSection(hdc, &BitmapInfo, DIB_RGB_COLORS, (void
No - CreateDIBSection does not initialize the bitmap. (Well - it initializes
it to zero) - the hDC is supplied mainly in cases where ... DIB_PAL_COLORS
is used - CreateDIBitmap will use the palette selected in the DC as the data
indexed by the BITMAPINFO struct.
Interestingly - you can pass CreateDIBSection the HANDLE you got when
creating a memory mapping of a bitmap file - In that case the DIBSection
*is* initialized with the contents of the file.
Chris
--
VisualC++ & Win32 FAQ: http://www.mvps.org/vcfaq
My Win32 Page: http://www.mvps.org/user32
Boom. Now you've got screen/window data in your dib section. Otherwise it
is all blackness--because the OS was kind enough to have initialized the
memory to 0 before giving it to you <g>.
OK, I think I'm not going to finalize the solution since I'm working on
another, safer method.
The problem with BitBlt is that it blits the front buffer, which is stupid.
The reason why I think it's stupid is that it's not safe.
If a window that is topmost, like a help window is in the way, it WILL get
BlitBlt.
I'm making an App that will be released to the public, and I don't want to
take risks. Try this with MS-Paint or any other graphics program, and you'll
see there are no problems with these. They use a secondary buffer.
V-man
Some applications write to the screen DC. BitBlit-ing from YOUR window DC
into an offscreen DC will copy the other window that is covering your
window.
Someones suggested that BitBlt may read from a back buffer or something. Not
sure, but I've seen enough to drop it.
You don't have to beleive me if you don't want to.
V-man
I too program commercial apps, and have never seen this behavior. This
pseudo code (pseudo because I'm not a compiler - I'll try to get as close as
my memory lets me :), inside a CWnd:
-----------------------------------
// get window's DC and size
CDC *pDC = GetDC();
CRect clientrect;
GetClientRect(&clientrect);
// create and size new DC
CDC myDC;
myDC.CreateCompatibleDC();
CBitmap myBMP;
myBMP.CreateCompatibleBitmap(pDC, &clientrect);
myDC.SelectObject(&myBMP);
myDC.BitBlt(0,0,clientrect.width(), clientrect.height(),pDC,0,0,SRCCOPY);
-------------------
copies the contents of the CWnd's client area into a memory device context,
and DOES NOT copy any windows, cursors, etc. that happen to be on top of it.
To test this, save myBMP out to a file after the BitBlt - you won't ever see
anything but what's drawn by the CWnd.
Hope this helps!
-Chris Bond
"V-man" <j_ca...@excie.com> wrote in message
news:O05kXy$#$GA.282@cppssbbsa05...
huh? Now I'm confused. A window DC is nothing more than a munged up device
(i.e. screen) DC. There is no system backbuffer for GDI to retrieve the
"actual" contents of a covered window.
If you BltBlt from such a screen DC you will get the contents of the video
memory - which will reflect any overlapping windows or any other @#%& that
happens to be in video memory there at the time.
The exception to this rule is the WS_EX_LAYERED windows maintained by Win2K
(and 98?). Backbuffers have to be maintened by the window manager to make
these babies work and they will not appear in Blits of normal windows (this
implies a disturbing level of indirection).
Nonetheless - as long as we can ignore WS_EX_LAYERED then no client area is
safe - blits from overlapped windows *will* capture the overlapping content.
Chris.
If yes, then keep reading:
go to www.excite.com
they have free internet access. The link is hard to find so do a search of
the entire page for the word "internet" or "Freelane" or "free" or "free
access" or "access".... you get the picture.
Download the exe and install (of course)
PS: if there is no local dial-up access, then ask some people to help you
find something similar.
OK, when you run that free internet access program, you get an advertizing
window. Put the window on your App and save the scene.
Prepare for a shock.
my address j[underscore]carbone[at_symbol]excite.com
If you have a solution to that. Let me know.
V-man
Chris Bond wrote in message ...
>V-man et. al,
>
> I too program commercial apps, and have never seen this behavior. This
>pseudo code (pseudo because I'm not a compiler - I'll try to get as close
as
>my memory lets me :), inside a CWnd:
>
>-----------------------------------
>// get window's DC and size
>CDC *pDC = GetDC();
>CRect clientrect;
>GetClientRect(&clientrect);
>
>// create and size new DC
>CDC myDC;
>myDC.CreateCompatibleDC();
>
>CBitmap myBMP;
>myBMP.CreateCompatibleBitmap(pDC, &clientrect);
>
>myDC.SelectObject(&myBMP);
>
>myDC.BitBlt(0,0,clientrect.width(), clientrect.height(),pDC,0,0,SRCCOPY);
>
>-------------------
>
>copies the contents of the CWnd's client area into a memory device context,
>and DOES NOT copy any windows, cursors, etc. that happen to be on top of
it.
>To test this, save myBMP out to a file after the BitBlt - you won't ever
see
>anything but what's drawn by the CWnd.
>