Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

BitBlt, GetDIBits and performance

1,679 views
Skip to first unread message

Samar Abbas Lotia

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
I am working on a routine which will translate the contents of a window to a
DIB. In my case performance is a major factor and I need to run through this
procedure as fast as possible. Some basic timings show that the slowest
items are the calls to GetDIBits and BitBlt.

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);
}
}
}

Jack Thornton

unread,
Jul 11, 2000, 3:00:00 AM7/11/00
to
Try creating a DIBSECTION (using CreateDIBSection) to blit into instead of a
compatable bitmap. After the blit is finished, the data will already be
available in DIB format (through the pvBits pointer) - no need for a
subsequent call to GetDIBits.

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...

V-man

unread,
Jul 28, 2000, 3:00:00 AM7/28/00
to

So how does one use CreateDIBSection()?

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>...

Graham Jones

unread,
Jul 29, 2000, 3:00:00 AM7/29/00
to
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

**)&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

V-man

unread,
Jul 29, 2000, 3:00:00 AM7/29/00
to
ok, I get it now, but just one tiny little thing. The pointer points to
complete blackness. Everything is zero, but the program runs fine and
creates the .BMP file without crashing.

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

Chris Becke

unread,
Jul 29, 2000, 3:00:00 AM7/29/00
to
"V-man" wrote:
> 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?

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


Phil Eamon

unread,
Jul 29, 2000, 3:00:00 AM7/29/00
to
V-man wrote:
>
> ok, I get it now, but just one tiny little thing. The pointer points to
> complete blackness. Everything is zero, but the program runs fine and
> creates the .BMP file without crashing.
>
> 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?
No. In order to get your screen pixels into your dibsection you need to:
- Create compatible dc
- Select your dibsection into it as if it were a simple bitmap (use the
handle)
- BitBlit from the read (window/screen) dc to this compatible dc.

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>.

V-man

unread,
Jul 30, 2000, 3:00:00 AM7/30/00
to

>- Create compatible dc
>- Select your dibsection into it as if it were a simple bitmap (use the
>handle)
>- BitBlit from the read (window/screen) dc to this compatible dc.
>
>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

Phil Eamon

unread,
Jul 30, 2000, 3:00:00 AM7/30/00
to
V-man wrote:
> 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.
Huh? I have a feeling you would benefit greatly from a couple of basic
Windows programming books -- like good old Pretzold, for example. Your blit
goes into a window your target DC belongs to, not to any window that
happened to be on screen. You truly don't need to worry about painting in
an unintended window, it is not likely to happen (unless you're using a
screen dc, but then your window is screen, so again, it is all rather
logical. Lay off your commercial development for a moment and read up on
the platform you're trying to write for.)

V-man

unread,
Aug 1, 2000, 3:00:00 AM8/1/00
to

Phil Eamon wrote in message <39847D1E...@blarney.att.net>...

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

Chris Bond

unread,
Aug 14, 2000, 3:00:00 AM8/14/00
to
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.

Hope this helps!

-Chris Bond


"V-man" <j_ca...@excie.com> wrote in message
news:O05kXy$#$GA.282@cppssbbsa05...

Chris Becke

unread,
Aug 15, 2000, 3:00:00 AM8/15/00
to

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.

V-man

unread,
Aug 20, 2000, 3:00:00 AM8/20/00
to
Are you interested in testing your app if I tell you how? Your code looks
similar to what I had before.

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.
>

0 new messages