Reputation: 11
I have an HBITMAP
handle to a device-dependent bitmap, resulting from this code:
// copy screen to bitmap
HDC hScreen = GetDC(NULL);//don't use hwnd, it doesn't work for non native windows
HDC hDC = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, w, h);
HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
BOOL bRet = BitBlt(hDC, 0, 0, w, h, hScreen, x1, y1, SRCCOPY);
I want to access (read-only) the bits of the bitmap, read some values, do some calculations, then discard it.
According to this answer, I shouldn't use GetDIBits()
or GetBitmapBits()
since they copy the data, but instead I should use:
BITMAP bitmap;
GetObject(hBitmap, sizeof(bitmap), (LPVOID)&bitmap);
But according to GetObject
's documentation:
If
hgdiobj
is a handle to a bitmap created by callingCreateDIBSection
, and the specified buffer is large enough, theGetObject
function returns aDIBSECTION
structure. In addition, thebmBits
member of theBITMAP
structure contained within theDIBSECTION
will contain a pointer to the bitmap's bit values.If
hgdiobj
is a handle to a bitmap created by any other means,GetObject
returns only the width, height, and color format information of the bitmap. You can obtain the bitmap's bit values by calling theGetDIBits
orGetBitmapBits
function.
Which is pointed to in a comment on the above answer:
According to this https://msdn.microsoft.com/en-us/library/dd144904(v=vs.85).aspx if bitmap is not created by
CreateDIBSection
bitmap.bmBit
pointer will be null.
So, is there anyway to access the bits of the bitmap (RGB values), without copying them?
If it helps, the device on which the bitmap is dependent is always a screen, so I guess it's always a 24bit or 32bit bitmap.
In this article, regarding how to save an HBITMAP
to a file, there's this section:
// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)
if (cClrBits < 24) pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << cClrBits));
// There is no RGBQUAD array for these formats: 24-bit-per-pixel or 32-bit-per-pixel
else pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
So, I don't really understand what's happening here, and which is right?
Upvotes: 0
Views: 371
Reputation: 18523
I shouldn't use
GetDIBits()
... since they copy the data ...
...
If it helps, the device on which the bitmap is dependent is always a screen, so I guess it's always a 24bit or 32bit bitmap.
Depending on the exact hardware that you use, pixels might be stored differently (maybe Rr Gg Bb
on one computer and Bb Gg Rr 00
on another one and RG Br gb
on a third).
To ensure that you know the data format, you should use GetDIBits()
because that function does not only copy the data but it also converts the data to a "known" format which does not depend on the hardware.
would using
GetPixel()
be more efficient than copying it?
If you only want to inspect a few pixels (e.g. you want to know the color of 10 of the pixels), it should be more efficient.
If you are interested in all 20000 pixels, GetDIBits()
should be more efficient.
pbmi = (PBITMAPINFO)LocalAlloc ...
So, I don't really understand what's happening here ...
GetDIBits()
supports various bitmap formats, for example:
In the case of "24-bit", the BITMAPINFO
structure consists only of a BITMAPINFOHEADER
structure. I myself often write the code like this in this case:
BITMAPINFOHEADER hdr;
...
GetDIBits(..., (BITMAPINFO *)&hdr, ...);
In the case of "256-color", the BITMAPINFO
structure consists of a BITMAPINFOHEADER
structure followed by 256 "R,G,B" tuples (the color map) - so the structure needs more memory compared to the "24-bit" case.
Please note that the bottom line of an image is stored first and there are padding bytes at the end of each line if the length of the line is not a multiple of 4 bytes.
Upvotes: 0