How could you copy the contents of an HDC to a bitmap?
Off the top of my head I think you need to:
Create a new DC compatible with the source DC. Call this the memory DC.
Create a new bitmap of the correct size.
Select the bitmap into the memory DC.
BitBlt the source DC into the memory DC.
The bitmap should now contain a copy of the source DC.
I'm at home so can't give you any code, so I hope this is enough to get you started. There is a good GDI section on Code Project.
http://www.codeproject.com/KB/graphics/
There is a good piece of sample code here that does just that (amongst other things).
I've used a similar technique before (many moons ago), but do not have the code to hand.
Related
I'm not exactly a windows programming expert ;) so please excuse me if this question is trivial.
I have a window on which I want to display a bitmap. The bitmap can be either stretched to span over the whole area or it will be displayed with original aspect ratio and empty space will be filled with a solid brush.
I load the bitmap with LoadImage and display it using BitBlt. I do it on WM_ERASEBKGND, I use the DC from wparam which is a mem DC.
I was thinking of using StretchBlt instead of BitBlt when the bitmap needs to be stretched.
So my questions are:
is it okay to store a bitmap as HBITMAP or should I use DIBSection? Which one is better performance-wise, what's the memory footprint of both solutions?
should I always stretch the bitmap when drawing to a DC on WM_ERASEBKGND, or should I create a compatible DC (or bitmap) with a precomputed stretched bitmap and then just BitBlt it to the target DC?
if I create a precomputed bitmap, should I immediately unload the original bitmap to save on memory?
should I use BitBlt/StretchBlt or CopyImage?
I read that I can also use LoadImage with desired width and height parameter, so that the loaded image is already stretched, is this solution better?
I'd be really grateful for some code examples.
Edit:
GDI+ solutions are welcome too. I'm interested in the best, easiest and best-performing solution for this problem.
I'm wondering , if I want to create different bitmaps,
I use the CreateCompatibleBitmap function again and again, to associate it to the same memory CDC.
is it the same meaning that I CreateBitmap and SelectObject again and again??
I ask this question because I want to do something to the newly created bitmap by another CDC.
Without seeing the specific code it's hard to know the exact problem but CreateCompatibleBitmap is commonly used in double-buffering situations to avoid flickering. Rather than drawing directly to the Device Context (DC) you first draw to an off-screen, or memory, DC which is basically drawing to a bitmap. The bitmap is then copied directly to the screen DC using BitBlt, so it appears like all the drawing happens at the same time.
The usual steps are this (and will probably happen on every WM_PAINT):
Use the screen DC to create a bitmap, which is 'compatible' with it, using CreateCompatibleBitmap.
Create a memory DC
Select the bitmap into the memory DC (this is what you'll draw to)
When drawing is finished BitBlt the memory DC's bitmap onto the screen DC.
More information available here: Guide to Win32 Memory DC (Code Project)
Yes, CreateCompatibleBitmap() creates a new bitmap, a new memory allocation, a new handler each time you call it in a loop;
It's only for 'debugging' purposes, so I don't want to spend a lot of time with this, nor it is very important. The program exports the data as a png, jpg, svg, etc... -so it's not a big deal, though it could be good to see the image while it is being generated. Also, the program is going to be used in a Linux server; but I'll limit this 'feature' to the Win version.
I also don't want to use a library, except if it is very, very lightweight (I used CImg for a while, but I wasn't very happy with its speed, so I ended up writing the important functions myself and just using libjpeg and libpng directly).
I have the image in an ARGB format (32bpp), though converting the format won't be a problem at all. I would like to use Win32, creating a window from a function deep inside the code (no known hInstance, etc), and writing the bitmap. Fast and easy, hopefully.
But I don't know the win32api enough. I've seen that the only option to draw (GDI) is trough a HBITMAP object... Any code snippet or example I can rely on? Any consideration I might not overlook? Or maybe -considering my time constrains- should I just forget it?
Thanks!
The biggest piece of work here is actually registering the window class and writing a minimal window procedure. But if this is debug only code, you can actually skip that part. (I'll come back to that later).
If you have an HBITMAP, then you would use BitBlt or StretchBlt to draw it, but if you don't already have the image as an HBITMAP, then StretchDIBits is probably a better choice since you can use it if you only have a pointer to the bitmap data. You have to pass it a source and destination rectangle, a BITMAPINFOHEADER and a pointer to the raw bitmap data. Something like this
SIZE sBmp = { 100, 200 };
LPBITMAPINFOHEADER pbi; // the bitmap header from the file, etc.
LPVOID pvBits; // the raw bitmap bits
StretchDIBits (hdc, 0, 0, sBmp.cx, sBmp.cy,
0, 0, sBmp.cx, sBmp.cy,
pvBits, pbi,
DIB_RGB_COLORS,
SRCCOPY);
So the next part is how do I get a HDC to draw in? Well for Debug code, I often draw directly to the screen. HDC hdc = GetDC(NULL) will get a DC that can draw to the screen, but there are security issues and it doesnt' work the same with Aero in Windows Vista, so the other way is to draw onto a window. If you have a window that you can just draw over, then HDC hdc = GetDC(hwnd) will work.
The advantage of doing it this way is that you don't have to create and show a window, so it's less disruptive of code flow, It's helpful for debugging a specific problem, but not the sort of thing you can leave turned on all of the time.
For a longer term solution, You could create a dialog box and put your bitmap drawing call in the WM_PAINT or WM_ERASEBKGND message handler for the dialog box. But I don't recommend that you show a dialog box from deep inside code that isn't supposed to be doing UI. Showing a window, especially a dialog window will interfere with normal message flow in your application. If you want to use a dialog box for this bitmap viewer, then you want that dialog window to be something that the User shows, and that you just draw onto if it's there.
If you don't have access to an HINSTANCE, it's still possible to show a dialog box, it's just more work. That's sort of a different question.
About all you need is a handle to a device context (HDC). To display your data on it:
CreateDibSection to create a DIBSection.
Copy your data to the memory block returned by CreateDibSection.
create a DC compatible with the target DC.
Select the DIBSection into your newly created DC.
BitBlt (or StretchBlt) from your DC to the target DC.
I'm writing an unmanaged Win32 C++ function that gets a handle to a bitmap, and I need to draw on it.
My problem is that to draw I need to get a device context, but when I do GetDC (NULL), it gives me a device context for the WINDOW! The parameter for GetDC () is a window handle (HWND), but I don't have a window; just a bitmap handle.
How can I draw on this bitmap? Thanks!
In addition to Pavel's answer, the "compatible with the screen" always bugged me too, but, since CreateCompatibleDC(NULL) is universally used for that purpose, I assume it is correct.
I think that the "compatible" thing is related just to DDB (the DC is set up to write on the correct DDB type for the current screen), but does not affect read/writes on DIBs.
So, to be safe, always use DIBs and not DDBs if you need to work on bitmaps that doesn't just have to go temporarily onscreen, nowadays the difference in performance is negligible. See here for more info about DIBs and DDBs.
CreateCompatibleDC() and SelectObject() your bitmap into it.
However, not every bitmap can be selected into any DC.
You might have to play with mapping mode and other options of memory DCs.
The basic win32 paradigm for drawing on a bitmap is that you select the bitmap onto a device context, after which, all drawing operations on that device context are stored in the bitmap. You then use one of the various 'blit' operations (e.g. StretchBlt) to transfer this to a display surface, which is just the device context of a window client area.
Others have provided better detail, this is just the high-level view.
Well, this is a bit outside the box.. I guess.. But I do know that Graphics can return a HDC, and Graphics take a Bitmap as an argument to its ctor . A Bitmap in turn can be created from a HBITMAP and a HPALETTE. The only problem here is that I do not know if the HPALETTE argument can be NULL.
Graphics* g;
Bitmap* bitmap;
HBITMAP _bitmap; // <- this one is yours
bitmap = Bitmap::FromHBITMAP(_bitmap, NULL);
g = new Graphics(bitmap);
HDC hdc = g->GetHDC();
// when done, call g->ReleaseHDC(hdc);
However, I would urge you to receive the HDC as an argument to your function as well.. I do not think that anyone will have a BITMAP and NOT have the DC to it.
If you're having these issues with finding a HDC to a HBITMAP, so will everyone else.
How could you copy the contents of an HDC to a bitmap?
Off the top of my head I think you need to:
Create a new DC compatible with the source DC. Call this the memory DC.
Create a new bitmap of the correct size.
Select the bitmap into the memory DC.
BitBlt the source DC into the memory DC.
The bitmap should now contain a copy of the source DC.
I'm at home so can't give you any code, so I hope this is enough to get you started. There is a good GDI section on Code Project.
http://www.codeproject.com/KB/graphics/
There is a good piece of sample code here that does just that (amongst other things).
I've used a similar technique before (many moons ago), but do not have the code to hand.