Transfer image from CDC to Windows Imaging Component (WIC)? - mfc

I have some old C++/MFC code which uses GDI to create an image in a device context (CDC), using functions like Rectangle. The image is then painted to the screen, by the destructor of CPaintDC. Everything works as expected.
Now I want to store the image in a PNG file. For this, I am using Windows Imaging Component (WIC). I can create an image in WIC by creating a bitmap frame, storing pixels in a buffer, and copying the pixels into it using WritePixels. Then WIC stores the image as a PNG file via Commit. All this also works.
The question is, how can I transfer the image I created using GDI, which is in a CDC, to something WIC recognizes? I'm looking for something more efficient than a CDC::GetPixel loop storing into a buffer followed by WritePixels.
Windows 7, Visual Studio 2015, C++.
Update: I'm trying to get the CImage method suggested by #Andrew Komiagin. My code is
CDC memdc;
memdc.CreateCompatibleDC(nullptr);
myControl.RenderToDC(memdc); // this draws the image onto the dc
CBitmap bmp;
BOOL ok=bmp.CreateCompatibleBitmap(&memdc, w, h); // w=h=292 defined elsewhere
CBitmap *pOldBitmap=memdc.SelectObject(&bmp);
ok=memdc.BitBlt(0, 0, w, h, &memdc, 0, 0, SRCCOPY);
CImage tempImageObj;
tempImageObj.Attach((HBITMAP)bmp.Detach());
CString outputFilename("outputImage.png");
HRESULT hr=tempImageObj.Save(outputFilename);
This produces a PNG image file with an all-black square, w x h pixels, rather than the image I drew. I know the image is being drawn correctly by RenderToDC (see below).
For comparison, this is in MyControl::OnPaint for the control (derived from CStatic):
CPaintDC dc(this); // device context for painting
RenderToDC(dc); // this draws the image onto the dc
// Painted to screen by CPaintDC's destructor
The image appears correctly.

I'd suggest using standard CImage class from ATL/MFC that works just great with GDI device context and natively supports the ability to load and save images in JPEG, GIF, BMP, and Portable Network Graphics (PNG) formats.
Here is an example on how to use it:
CDC MemDC;
MemDC.CreateCompatibleDC(&dc);
CBitmap Bmp;
Bmp.CreateCompatibleBitmap(&dc,ClientRect.Width(),ClientRect.Height());
MemDC.SelectObject(&Bmp);
MemDC.BitBlt(0,0,ClientRect.Width(),ClientRect.Height(),&dc,0,0,SRCCOPY);
CImage TempImageObj;
TempImageObj.Attach((HBITMAP)Bmp.Detach());
TempImageObj.Save(sFilePath);

Related

How to create Gdiplus::Bitmap from CDC

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.

Draw WICBitmap to window?

I have a WICBitmap that contains an image in my MFC program. Is there any way to draw this bitmap onto a device context?
void DrawBitmap(IWICBitmapSource source, HDC targetDC, int X, int Y, int cx, int cy)
{
//source: The Bitmap to draw
//TargetDC: The HDC to draw onto (e.g. a printer or screen DC)
//X,Y: The location on the DC to draw the bitmap
}
There are a number of samples on MSDN that show how to display a WIC bitmap using, for example, GDI, GDI+, Direct2D etc.
MSDN: Image Decoding Samples (archive)
Introduction to WIC: How to use WIC to load an image, and draw it with GDI? (archive)
Microsoft provides a WIC Image Viewer Using GDI Sample (GitHub mirror)
The basic idea is:
convert IWicBitmapSource into a standard Windows BITMAP (CreateDibSectionFromBitmapSource)
draw using the BITMAP using your standard tools
The file can be edited separately as bmp file, and after you can load WIC object as you can see in How to Load a Bitmap from a File.

Display IPLimage/ MAT (opencv) in MFC picture box

I want to display an IPLimage / MAT (opencv) formats on a MFC picture box in Visual C++
Here is a complete solution describing how to display an IplImage in a MCF/C++ form application using OpenCV http://ac-it.pl/display-an-iplimage-in-a-mcfc-form-application-using-opencv
Picture boxes can only display bitmaps I think. You'll need to convert IPLimage to a bitmap.
Assuming you can first convert IPLimage to a buffer of RGB values, see Creating HBITMAP from memory buffer
Then when you get the HBITMAP, you'll need to load it in the Picture Box. Assuming by picture box you mean a static control, add SS_BITMAP to its styles, and then load the HBITMAP using
SendMessage(hStatic, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);

GDI+ only draws monochrome on memory DC

I'm trying to do some double buffering in an MFC application and trying to draw on the memory DC with GDI+. However, although I called CreateCompatibleDC(), I'm only getting a monochrome image. Here is the code:
CDC bufferDC;
CBitmap bufferBitmap;
bufferDC.CreateCompatibleDC(&dc);
bufferBitmap.CreateCompatibleBitmap(&bufferDC, 300, 300);
bufferDC.SelectObject(bufferBitmap);
Graphics g(bufferDC);
g.Clear(Color::Green);
dc.BitBlt(0, 0, 300, 300, &bufferDC, 0, 0, SRCCOPY);
Instead of a green patch, I see a rectangle of dithered black and white dots. I even tried to save the bitmap to disk after the g.Clear() call. It is indeed a 1-bit depth file.
Any ideas what went wrong? Thanks.
A common mistake. A memory DC takes on the properties of the bitmap selected into it, no matter what compatibility it was created with. The default bitmap selected into a DC is monochrome. If you create a bitmap compatible with that DC, it will be monochrome too.
Create the bitmap to be compatible with the original DC, not the memory DC.
Both the bitnmap and the bufferDC should be compatible with dc (whatever device it refers to), not the bitmap compatible ... with its own DC.
Try to give &dc to CreateCopmpatibleBitmap.
Your code snippet does not show where the dc variable comes from. ThIs guy probably contains a monochrome bitmap, the default. You dont need it anyway. Instead, pass NULL to CreateCompatibleDC and it will be the same format as your display, which is probably color.

How to Convert a gdi+ Bitmap-like struct into an HDC?

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.