I am trying to create a Gdiplus::Bitmap from a device context. The function I use is:
Bitmap bitmap((HBITMAP)myDC.GetCurrentBitmap(), (HPALETTE)myDC.GetCurrentPalette());
...but when I draw the bitmap on the screen, all I see is a black rectangle. I think I'm using the Bitmap constructor wrong, because in docs it's written:
Do not pass to the GDI+ Bitmap::Bitmap constructor a GDI bitmap or a
GDI palette that is currently (or was previously) selected into a
device context.
But I have no idea how to go around this. Another approach I tried is using:
To capture the preexisting image from a window, a Windows Graphics Device Interface (GDI) function such as BitBlt() or StretchBlt() would have to be used to copy the image from the screen to a memory bitmap. This memory bitmap could then be used in the overloaded Bitmap constructor, which takes an HBITMAP as a parameter.
But I couldn't achieve this either.
Related
We're currently shifting an older application to draw through GDI+, instead of using GDI directly. As we are progressively translating teh system as we go, sometimes we need to grab a HDC from a Gdiplus::Graphics object in order to allow code which hasn't been translated yet to draw straight to it using GDI.
The drawing happens fine, except we seem to be losing antialias on images drawn directly to the DC using GDI. If, after grabbing the DC from the Graphics object, we draw a filled rectangle over the entire area, and then proceed with the drawing, it comes out fine. If we just get straight to drawing everything comes in without antialias.
void Draw(Gdiplus::Graphics& renderContext)
{
auto hdc = renderContext.GetHDC();
auto dc = HDC::FromHandle(nativeDC);
//Required to antialias drawing below
dc->FillSolidRect(GetClientRect(), RGB(255, 255, 255));
/* Do Drawing */
dc ->Detach();
renderContext.ReleaseHDC(hdc );
}
To be more precise, it seems like the antialias alpha get's flattened, which explains why filling a rectangle in GDI before drawing removes the artifacts.
It's a similar effect you might get if you draw with antialias on onto one Bitmap, and then try to alphablend it on top of another Bitmap - the alpha information on the top gets flattened and then the new alpha value specified in a ColorMatrix is applied to the whole image.
If anyone could provide some insight into what exactly is going on when you grab/release a HDC from a graphics object, and why drawing with GDI directly looses the alpha, I'd be appreciated.
The bitmap backing the HDC is a copy, not the original, as described here.
Using GDI on a GDI+ Graphics Object Backed by a Bitmap
When Graphics::GetHDC() is called for a Graphics object that is backed
by a bitmap rather than the screen, a memory HDC is created and a new
HBITMAP is created and selected into the memory HDC. This new memory
bitmap is not initialized with the original bitmap's image but rather
with a sentinel pattern, which allows GDI+ to track changes to the
bitmap. Any changes that are made to the memory bitmap through the use
of GDI code become apparent in changes to the sentinel pattern. When
Graphics::ReleaseHDC() is called, those changes are copied back to the
original bitmap... Also, there is a performance cost to this approach because
GDI+ must copy the changes back to the original bitmap.
Obviously when you draw on an HDC with GDI you won't get any antialiasing. GDI doesn't support it. That's what GDI+ is for.
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;
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
:)
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 to Convert a Bitmap-like struct into an HDC?
I am now writting image processing program in c++, gdi.
If I got a HDC.
I can draw whatever I like on the HDC in gdi by the following code.
// HDC is handy.
HDC dc;
dc.DrawXXX // I can draw using gdi method.
Graphics gr(dc); // now I can also draw on the dc using gdi+ method.
My Application is based on FreeImage.
I make of fipImage. ( use data struct like Bitmap )
However if I want to draw on fipWinImage, now I have to copy fipWinImageto Bitmap, then draw on the Bitmap, and finally convert the bitmap into fipImage again, which is time comsuming and memory comsuming.
Convert fipImage to Bitmap -> Draw on the bitmap -> convert bitmap to fipWinImage
fipWinImage imagefip;
Bitmap* tempImg = new Bitmap(imagefip->GetWidth(), imagefip.GetHeigt(), PixelFormat24bppRGB); // memory comsuming is image is large
Graphics *pGr = Graphics::FromImage(tempImg);
HDC dc = pGr->GetHDC();
RECT rec;
rec.left = 0;
rec.top = 0;
rec.right = imagefip.GetWidth();
rec.bottom = imagefip.GetHeight();
fipImage.draw(dc, rec); // using stretchdibits()
pGr->ReleaseHDC(dc);
Graphics gr(tempImg);
HDC dc = gr.GetHDC(); // Get an Hdc, draw using gdi method
gr.ReleaseHDC(tempDC); //
gr.drawXXX // Draw using gdi+ method.
fipWinImage fipImg; // final result fipWinImage.
HBITMAP temp;
Color color;
tempImg->GetHBITMAP(color, &temp);
fipImg->copyFromBitmap(temp);
I want to construct a HDC directly from fipImage. and draw directly on fipWinImage
How can I do this?
First a few clarifications:
A Device Context is basically a structure that remembers things like foreground and background colors, brushes, font info, and the physical drawing surface (bitmap).
This is a handy thing, so that you don't have to keep specifying all of these things when you're doing one graphics operation after another. You can also pass all of these settings around more easily this way. That's all that a DC really is - just a collection of drawing parameters, including the surface to draw upon.
An "HDC" is just a handle (reference) to one of these structs. Being a "Handle" lets window move the struct around in memory to manage free space without your pointers to it getting messed up.
If you have access to the source code for the library you're using, examine the fipWinImage::draw(...) method. If they're using StretchDIBits, then they must get their raw bitmap data into a compatible format at some point. It's also possible that the fipWinImage class is wrapping an underlying BITMAP or DIB, etc.
The final step to getting your own HDC...
A bitmap is "SELECTED" into a device context, and can only be selected into a single DC at one time. If you can get the internal HBITMAP from fipWinImage, you can select it into another DC (assuming that it isn't still selected into another HC).
When you create a DC, windows automatically creates a 1x1 bitmap for it (since a DC must have a selected bitmap at all times). When you select in a new bitmap, you get the handle to the previously selected bitmap returned to you. Hang on to that, because you're going to need to put it back when you're done.
Hope that helps.
I don't know FreeImage, but if you can get a pointer to the actual pixel data (DIB section) out of it, you could just create a HBITMAP that shares it without having to copy the data every time.