Drawing bitmap from memory - c++

I need to create the HBITMAP.
Here lies the problem. I have the bmp file's content in memory.
I know how to create a HBITMAP if the bitmap was as a resource.
But since it is in memory, I don't know how to do it.
I do it like this (if in resource) : Link
hDC = BeginPaint(hWnd, &Ps);
// Load the bitmap from the resource
bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_EXERCISING));
// Create a memory device compatible with the above DC variable
MemDCExercising = CreateCompatibleDC(hDC);
// Select the new bitmap
SelectObject(MemDCExercising, bmpExercising);
// Copy the bits from the memory DC into the current dc
BitBlt(hDC, 10, 10, 450, 400, MemDCExercising, 0, 0, SRCCOPY);
// Restore the old bitmap
DeleteDC(MemDCExercising);
DeleteObject(bmpExercising);
EndPaint(hWnd, &Ps);
Please guide me on how to do it if it were a memory resource.
Somehow change char img[10000] into a resource ?
Here, img is the memory contraining the contents of the bitmap.

First, let's remove a little innocent gotcha:
hDC = BeginPaint(hWnd, &Ps);
// Load the bitmap from the resource
bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_EXERCISING));
// Create a memory device compatible with the above DC variable
MemDCExercising = CreateCompatibleDC(hDC);
// Select the new bitmap
HOBJECT oldbmp = SelectObject(MemDCExercising, bmpExercising); //<<<<save it for later ...
// Copy the bits from the memory DC into the current dc
BitBlt(hDC, 10, 10, 450, 400, MemDCExercising, 0, 0, SRCCOPY);
// Restore the old bitmap
SelectObject(MemDCExercising, oldbmp); //<<<... DeleteDC will leak memory if it holds a resource
DeleteDC(MemDCExercising);
DeleteObject(bmpExercising);
EndPaint(hWnd, &Ps);
Now, an HBITMAP is (conceptually speaking) a pointer to an internal structure that holds a "pointer" (in fact is much more a stream) towards the GDI memory space you cannot access.
A "memory bitmap" is not represented into your program as a memory buffer that belogs to your program, but as ... an HBITMAP obtained with CreateCompatibleBitmap, where the HDC parameter id the DC the bitmap has to be compatible with. (usially a screen, window or painting DC).
You can cerate an initialized bitmap passing a buffer containing initial data, or get the data a bitmap holds with CreateBitmap or GetBitmapBits.
In any case, these are your local copy of the bitmap data, not the "live bitmap" GDI draws in.
Note also that the internal structure of those data depends on the format (how many bits per pixel on how many planes and with or without a palette) the bitmap needs to have, and that, to avoid performance penalty in the Blit process, it must coincide with the format used by your screen setup.
This does not necessarily have to be the same as the one the bitmap has when saved into a "bmp" file.

Related

Why do I need to save handle to an old bitmap while drawing with Win32 GDI?

Here is the code from switch in WndProc function I've been given as an example:
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Create a system memory device context.
bmHDC = CreateCompatibleDC(hdc);
// Hook up the bitmap to the bmHDC.
oldBM = (HBITMAP)SelectObject(bmHDC, ghBitMap);
// Now copy the pixels from the bitmap bmHDC has selected
// to the pixels from the client area hdc has selected.
BitBlt(
hdc, // Destination DC.
0, // 'left' coordinate of destination rectangle.
0, // 'top' coordinate of destination rectangle.
bmWidth, // 'right' coordinate of destination rectangle.
bmHeight, // 'bottom' coordinate of destination rectangle.
bmHDC, // Bitmap source DC.
0, // 'left' coordinate of source rectangle.
0, // 'top' coordinate of source rectangle.
SRCCOPY); // Copy the source pixels directly
// to the destination pixels
// Select the originally loaded bitmap.
SelectObject(bmHDC, oldBM);
// Delete the system memory device context.
DeleteDC(bmHDC);
EndPaint(hWnd, &ps);
return 0;
My question is why is it necessary to save and restore the return value of SelectObject() in oldBM?
why is it necessary to save and restore the return value of SelectObject() in oldBM?
BeginPaint() gives you an HDC that already has a default HBITMAP selected into it. You are then replacing that with your own HBITMAP. You did not allocate the original HBITMAP and do not own it, BeginPaint() allocated it. You must restore the original HBITMAP when you are done using the HDC so that EndPaint() can free it when destroying the HDC, otherwise it will be leaked.

Can I create more than one bitmaps for compatible DC?

Is it right to create two bitmaps for one DC?
My situation is I have
dc = CreateCompatibleDC(NULL);
bitmap = CreateDIBSection(dc, pbmi1, DIB_RGB_COLORS, (void **) &bmpBits, NULL, 0);
extra_bitmap = CreateDIBSection(dc, pbmi2, DIB_RGB_COLORS, (void **) &extraBmpBits, NULL, 0);
The difference is: bitmap is width*height , extra_bitmap is width/2*height*2
I need to show both images on the screen according to requirements from users.
I tried these code above, it can run (based only on my limited test). But I am not sure if it is the right way to do it. Any suggestions and/or comments are welcome. Thanks.
By the way, if I can have two bitmaps associated with one DC, what is the right way to release them? Can I just call DeleteDC(dc)? Thanks.
Bitmaps are only associated with a DC when they're selected into them via SelectObject. The DC you pass to the CreateDIBSection is only used to define the layout/palette of the newly created bitmap, and only in some circumstances, but it doesn't irrevocably associate that bitmap with the DC or anything like that.
To draw a bitmap to a window, it needs to be selected into a DC (the "source DC"), and this is where you can only have one at a time.
For example:
HDC hdcTarget = GetDC(hWnd); // or hdcTarget = BeginPaint(...)
HDC hdcSource = CreateCompatibleDC(hdcTarget); // create a "source DC")
HGDIOBJ hOldBmp = SelectObject(dc, bitmap); // select bitmap 1 in
BitBlt(hdcTarget, x, y, w, h, hdcSource, 0, 0, SRCCOPY); // draw bitmap 1
SelectObject(hdcSource, extra_bitmap); // select bitmap 2 in
BitBlt(hdcTarget, x1, y1, w1, h1, hdcSource, 0, 0, SRCCOPY); // draw bitmap 2
SelectObject(hdcSource, hOldBmp); // restore previous bitmap
DeleteDC(hdcSource); // no longer needed
ReleaseDC(hWnd, hdcTarget); // or EndPaint(...)
After search around for a few hours, I get
http://www.ucancode.net/Visual_C_MFC_Samples/CreateDIBSection-BITMAPINFOHEADER-CreateCompatibleDC-BITMAPINFO.htm
In this example:
// Create HDCs to hold our surfaces.
hdcSrc1 = CreateCompatibleDC(hdcDest);
if (!hdcSrc1) goto HANDLEERROR;
hdcSrc2 = CreateCompatibleDC(hdcDest);
if (!hdcSrc2) goto HANDLEERROR;
For delete:
DeleteDC(hdcSrc1);
DeleteDC(hdcSrc2);
DeleteObject(hbmSrc1); // hbmSrc1 and hbmSrc2 are created using hbm = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS,(void **)&pBits, NULL, 0);
DeleteObject(hbmSrc2);
Hope this can be helpful for others. thanks.
You may create as many in-memory bitmaps as you like.
You may create as many device-dependent DCs as you like.
A bitmap may be selected into only one DC at a time. If you try to select the same bitmap into multiple DCs, then you will get unpredictable behavior.
A DC will never have more that one bitmap selected into it at a time, because the act of selecting one in selects the previous one out.
Don't delete a memory DC while your bitmap is still selected into it. You should select the original bitmap (which is a monochrome 1x1 bitmap) into the DC to get your bitmap out before you delete the DC.
Don't delete an in-memory bitmap while it's still selected into a DC.

Create a HBITMAP which points to an existing memory buffer

I am using the FreeImage library to store and manipulate bitmap data. Part of my code requires me to take a screenshot of a window (in Windows), and store it as a FBITMAP* (FreeImage's bitmap data structure). The method I have worked out of doing this involves two steps: capture the image, then convert it to a FBITMAP*.
To capture the image, I do something like this:
HWND window; // Assume this is a valid handle to my window
int width; // width of window client area
int height; // height of window client area
HDC windowDC = GetDC(window);
HDC captureDC = CreateCompatibleDC(windowDC);
HBITMAP screenshot = CreateCompatibleBitmap(windowDC, width, height);
SelectObject(captureDC, screenshot);
BitBlt(captureDC, 0, 0, width, height,
captureDC, 0, 0, SRCCOPY|CAPTUREBLT);
ReleaseDC(window, windowDC);
DeleteDC(captureDC);
FreeImage provides a function which returns a raw pointer to the pixel data:
BYTE* FreeImage_GetBits(FBITMAP*)
The FAQ explains that a HBITMAP (WinAPI handle to a bitmap) can be converted to a FBITMAP* using GetDIBits, which takes a source HBITMAP and a destination raw pointer as arguments, and copies the pixel data from one to the other.
The problem with this approach is that I have copied the data twice - once in the BitBlt from the window DC to the HBITMAP selected in the memory DC, and then again from the HBITMAP to the FreeImage memory buffer. I wish to remove this inefficiency and copy the data directly to my raw pointer in the BitBlt operation. For this to work, I need a memory DC which has a HBITMAP selected into it, and where that HBITMAP points to my memory buffer instead of to memory that Windows allocated for it.
How can I achieve this?

Render Buffer on Screen in Windows

I'm searching for a way rendering a char buffer onto the content-area of a window. This is just pseudo but intended to demonstrate what I actually want to do:
char buffer[300][200][3]; // 300px x 200px x RGB bytes
// ... render stuff into buffer
FancyWindowsFunctionToRenderBufferOnWindow(my_hwnd, buffer, 300, 200, offset_x, offset_y);
Is there a way to do something similar?
I think you need to create a device independent bitmap (DIB). If you already have an array of pixels that is ready to be put on an application window, you may need to copy the whole array to the buffer allocated by the CreateDIBSection API and call BitBlt to transfer the DIB to the window. This is the only way I know to show a mere array of pixels as a visible picture on the computer screen on Win32 platform and it is highly complicated and difficult to understand.
Here are the steps I used to take to test things similar to what you want to do:
Creating DIB:
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = /* Width of your image buffer */
bmi.bmiHeader.biHeight = - /* Height of your image buffer */
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
HDC hDesktopDC = GetDC(GetDesktopWindow());
HBITMAP hDib = CreateDIBSection(hDesktopDC, &bmi, DIB_RGB_COLORS, (void **)&buffer, 0, 0);
if (buffer == NULL) { /* ERROR */ }
HDC hDibDC = CreateCompatibleDC(hDesktopDC);
HGDIOBJ hOldObj = SelectObject(hDibDC, hDib);
/* Copy your array of pixels to buffer allocated above. */
ReleaseDC(GetDesktopWindow(), hDesktopDC);
Implementing WM_PAINT event handler (the hWnd variable holds the window handle below):
case WM_PAINT:
PAINTSTRUCT paint;
HDC hWndDc = BeginPaint(hWnd, &paint);
BitBlt(hWndDC, 0, 0, /* Width of DIB */, /* Height of DIB */,
/* HDC of DIB (hDibDC in the above) */, 0, 0, SRCCOPY);
EndPaint(hWnd, &paint);
break;
I don't really expect the above code snippets would directly help you. If you are determined to use GDI functions like ones in the above snippets, I recommend you to read very carefully their API documents on MSDN. Because it is very tricky to properly release or delete DCs or GDI objects acquired during using the APIs.
It sounds like you have an image (raster) stored as an array of chars (which is an odd choice, since you'd usually want an array of unsigned chars for raw bitmap images).
If you meet certain alignment constraints, you can display your bitmap pretty directly with SetDIBits. You fill out a BITMAPINFO structure that describes the pixel format and image dimensions, and then you pass that along with your data to SetDIBits. It'll paint them to a DC. It can be a little tricky to get all the parameters right.
The alignment requirement is that each scanline must begin on a 4-byte boundary. If you don't meet that requirement, you'll get garbage similar to having the wrong stride. You can make a copy of the data with the correct alignment if necessary.

deleting HBITMAP causes an access violation at runtime

I have the following code to take a screenshot of a window, and get the colour of a specific pixel in it:
void ProcessScreenshot(HWND hwnd){
HDC WinDC;
HDC CopyDC;
HBITMAP hBitmap;
RECT rt;
GetClientRect (hwnd, &rt);
WinDC = GetDC (hwnd);
CopyDC = CreateCompatibleDC (WinDC);
//Create a bitmap compatible with the DC
hBitmap = CreateCompatibleBitmap (WinDC,
rt.right - rt.left, //width
rt.bottom - rt.top);//height
SelectObject (CopyDC, hBitmap);
BitBlt (CopyDC, //destination
0,0,
rt.right - rt.left, //width
rt.bottom - rt.top, //height
WinDC, //source
0, 0,
SRCCOPY);
COLORREF col = ::GetPixel(CopyDC,145,293);
// Do some stuff with the pixel colour....
delete hBitmap;
ReleaseDC(hwnd, WinDC);
ReleaseDC(hwnd, CopyDC);
}
the line 'delete hBitmap;' causes a runtime error: an access violation. I guess I can't just delete it like that?
Because bitmaps take up a lot of space, if I don't get rid of it I will end up with a huge memory leak. My question is: Does releasing the DC the HBITMAP is from deal with this, or does it stick around even after I have released the DC? If the later is the case, how do I correctly get rid of the HBITMAP?
You must destroy GDI objects with DeleteObject, not delete. The latter is only used to free objects allocated using new.
delete should only be used to deallocate things allocated via new.
HBITMAP is a bitmap handle and you need to release the associated object using the GDI function DeleteObject.
Strictly, you should save the result of SelectObject from when you selected the bitmap into the device context and pass that to another call to SelectObject to ensure that the bitmap is not in use by the device context when you call DeleteObject. Things often work if you don't do this, especially if you're about to release the device context anyway but it is safest to do so.