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
hgdiobjis a handle to a bitmap created by callingCreateDIBSection, and the specified buffer is large enough, theGetObjectfunction returns aDIBSECTIONstructure. In addition, thebmBitsmember of theBITMAPstructure contained within theDIBSECTIONwill contain a pointer to the bitmap's bit values.If
hgdiobjis a handle to a bitmap created by any other means,GetObjectreturns only the width, height, and color format information of the bitmap. You can obtain the bitmap's bit values by calling theGetDIBitsorGetBitmapBitsfunction.
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
CreateDIBSectionbitmap.bmBitpointer 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?
Depending on the exact hardware that you use, pixels might be stored differently (maybe
Rr Gg Bbon one computer andBb Gg Rr 00on another one andRG Br gbon 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.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.GetDIBits()supports various bitmap formats, for example:In the case of "24-bit", the
BITMAPINFOstructure consists only of aBITMAPINFOHEADERstructure. I myself often write the code like this in this case:In the case of "256-color", the
BITMAPINFOstructure consists of aBITMAPINFOHEADERstructure 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.