GDI - How to create and fill bitmap? - c++

Someone can give me short explanation how to create bitmap runtime using GDI/GDI+ and to fill it with color ?
Thanks in advance.

CreateBitmap, CreateCompatibleBitmap or CreateDIBSection (in case you want access to raw underlying data bits)
CreateCompatibleDC
SelectObject the bitmap into created device context
FillRect or friends on the device context, and the painting takes place on your selected bitmap (there are options there: standard brushes for black and white, having RGB on hands instead of creating a brush you can do SetBkColor + ExtTextOut with an empty string and ETO_OPAQUE and the rectangle will be filled)
SelectObject back
The bitmap remains to hold the painting
Release the resources
Still it has something to do with "entire screen" in the title, and you need explain what you want there.

Query screen size
Create your drawable (or just manipulate the graphics object in your paint handler)
Fill it with color
:)

Related

What's the best way to store, strech and display a bitmap using GDI?

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.

CreateCompatibleBitmap Vs SelectObject

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;

WinAPI - avoid redraw of window

I'm drawing into a WinAPI-Window by using the SetPixel()-Function.
If I scale the window or lose focus (another window is on top) I lose the whole content that I draw into the window.
I just used
RECT rc;
GetClientRect(hwnd, &rc);
RedrawWindow(hwnd, &rc, NULL, RDW_NOERASE | RDW_NOFRAME | RDW_VALIDATE);
which helped to avoid redrawing the content when I move the window but scaling and losing focus still removes the content.
Does anyone have an idea what I missed?
Draw it to a buffer/bitmap and then draw that to your window.
When a window needs to be repainted it will be sent a WM_PAINT message. At this point you must redraw all of the window, or at least all parts of it which are contained within a clipping region. Windows does some buffering and automatic painting, specifically it will repaint parts of a window which are covered by other windows then uncovered. Once the window has been resized though, or (presumably) invalidated, you're on your own.
As #daniel suggested, if painting is an intensive process and you don't want to do it every time a repaint is required, render your content into a bitmap (which in this case will be an off-screen buffer) and BitBlt (copy) it into the window as necessary.
Grab yourself a copy of Charles Petzold's book "Programming Windows" for information about how you should go about painting. If you are writing a WinAPI app but have used SetPixel I'd recommend reading the entirety of the first few chapters to get an idea of how an old-school Windows programme should be structured.
SetPixel is very slow, you cannot improve your program significantly. Create in-memory bitmap and draw it on the window. For example, you can do this using StretchDIBits function, which draws the whole memory area as bitmap to the window, instead of SetPixel.
The most important StretchDIBits parameters are:
CONST VOID *lpBits - memory array (pixels). You need to fill it in memory instead of SetPixel calls.
CONST BITMAPINFO *lpBitsInfo - BITMAPINFO structure which must describe bitmap structure. For example, if lpBits has BGRW structure (4 bytes per pixel), BITMAPINFO must describe true color bitmap.
You need to draw the content into memory and then draw it to the window when you got WM_PAINT message. There is no way to avoid using memory buffer because window device context does not save what you draw.
Create a DIB surface and draw into it instead. Then redraw the bitmap when redrawing a window.
You're trying to draw with a pre-Windows way in Windows. ;)

How to draw on given bitmap handle (C++ / Win32)?

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.

Transparent window containing opaque text and buttons

I'm creating a non-intrusive popup window to notify the user when processing a time-consuming operation. At the moment I'm setting its transparency by calling SetLayeredWindowAttributes which gives me a reasonable result:
alt text http://img6.imageshack.us/img6/3144/transparentn.jpg
However I'd like the text and close button to appear opaque (it doesn't quite look right with white text) while keeping the background transparent - is there a way of doing this?
In order to do "proper" alpha in a layered window you need to supply the window manager with a PARGB bitmap by a call to UpdateLayeredWindow.
The cleanest way to achieve this that I know of is the following:
Create a GDI+ Bitmap object with the PixelFormat32bppPARGB pixel format.
Create a Graphics object to draw in this Bitmap object.
Do all your drawing into this object using GDI+.
Destroy the Graphics object created in step 2.
Call the GetHBITMAP method on the Bitmap object to get a Windows HBITMAP.
Destroy the Bitmap object.
Create a memory DC using CreateCompatibleDC and select the HBITMAP from step 5 into it.
Call UpdateLayeredWindow using the memory DC as a source.
Select previous bitmap and delete the memory DC.
Destroy the HBITMAP created in step 5.
This method should allow you to control the alpha channel of everything that is drawn: transparent for the background, opaque for the text and button.
Also, since you are going to be outputting text, I recommend that you call SystemParametersInfo to get the default antialiasing setting (SPI_GETFONTSMOOTHING), and then the SetTextRenderingHint on the Graphics object to set the antialiasing type to the same type that is configured by the user, for a nicer look.
I suspect you'll need two top level windows rather than one - one that has the alpha blend and a second that is display above the first with the opaque text and button but with a transparent background. To accomplish this with a single window you'll need to use the UpdateLayeredWindow API call, but using this will cause your buttons to not redraw when they are interacted with (hover highlights, focus etc.)
It is possible that if this application is for Vista only there is a new API call that you can use, but I do not believe it is available in XP or earlier.
I can't say for sure, you'll need to try it, but since everything is a window, you could try setting the layered attributes for your button to make it opaque.
As for the text, you may be able to put that in its own frame with a set background and foreground color, and modify its layered attributes to make the background color transparent...
But since these are child windows and not the top-level window, I really don't know that it'll work.