Gdiplus: DrawImage not working
-
Hi all, I need some help from you: I try to render an SVG image on the screen (with alpha channel). The problem is, when I try to draw the image on the screen, I see absolutely nothing. First of all, my SVG image is loaded correctly, and the ATL CImage from the below code, contains a correct image. The problem start when I try to use Gdiplus + alpha channel. For instance, if I use PixelFormat24bppRGB instead of PixelFormat32bppARGB, the image is drawn correctly, but alpha channel is not preserved - a black halo is shown around my image. Do you see any problem in my code? PS: I use Win7, 32 bit + Visual Studio 2013 Ultimate. Many thanks!
void CAppView::OnDraw(CDC* pDC)
{int width = 600, height = 600; GError\* pError = NULL; rsvg\_init(); g\_my\_svg = rsvg\_handle\_new\_from\_file("d:\\\\myImage.svg", &pError); rsvg\_handle\_get\_dimensions(g\_my\_svg, &g\_dimension); cairo\_surface\_t \*surface = cairo\_win32\_surface\_create\_with\_dib(CAIRO\_FORMAT\_ARGB32, width, height); cairo\_t\* cr = cairo\_create(surface); rsvg\_handle\_render\_cairo(g\_my\_svg, cr); HDC srcHDC = cairo\_win32\_surface\_get\_dc(surface); // Create ATL CImage, then, copy the content of srcHDC in the CImage HDC CImage image; image.Create(width, height, 32); HDC imageHDC = image.GetDC(); TransparentBlt(imageHDC, 0, 0, width, height, srcHDC, 0, 0, width, height, RGB(0, 0, 0)); // Initialize Gdiplus Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG\_PTR gdiplusToken; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// Problems starts from this point.
// Create a Gdiplus bitmap, and copy the content of CImage in bitmap, then write the bitmap on the screen. Gdiplus::Bitmap bmp(image.GetWidth(), image.GetHeight(), image.GetPitch(), PixelFormat32bppARGB, static\_cast(image.GetBits())); Gdiplus::Graphics graphics(pDC->GetSafeHdc()); graphics.DrawImage(&bmp, Gdiplus::Rect(0, 0, width, height)); Gdiplus::GdiplusShutdown(gdiplusToken); image.ReleaseDC(); image.Destroy(); cairo\_surface\_flush(surface); cairo\_destroy(cr); cairo\_surface\_destroy(surface);
}
-
Hi all, I need some help from you: I try to render an SVG image on the screen (with alpha channel). The problem is, when I try to draw the image on the screen, I see absolutely nothing. First of all, my SVG image is loaded correctly, and the ATL CImage from the below code, contains a correct image. The problem start when I try to use Gdiplus + alpha channel. For instance, if I use PixelFormat24bppRGB instead of PixelFormat32bppARGB, the image is drawn correctly, but alpha channel is not preserved - a black halo is shown around my image. Do you see any problem in my code? PS: I use Win7, 32 bit + Visual Studio 2013 Ultimate. Many thanks!
void CAppView::OnDraw(CDC* pDC)
{int width = 600, height = 600; GError\* pError = NULL; rsvg\_init(); g\_my\_svg = rsvg\_handle\_new\_from\_file("d:\\\\myImage.svg", &pError); rsvg\_handle\_get\_dimensions(g\_my\_svg, &g\_dimension); cairo\_surface\_t \*surface = cairo\_win32\_surface\_create\_with\_dib(CAIRO\_FORMAT\_ARGB32, width, height); cairo\_t\* cr = cairo\_create(surface); rsvg\_handle\_render\_cairo(g\_my\_svg, cr); HDC srcHDC = cairo\_win32\_surface\_get\_dc(surface); // Create ATL CImage, then, copy the content of srcHDC in the CImage HDC CImage image; image.Create(width, height, 32); HDC imageHDC = image.GetDC(); TransparentBlt(imageHDC, 0, 0, width, height, srcHDC, 0, 0, width, height, RGB(0, 0, 0)); // Initialize Gdiplus Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG\_PTR gdiplusToken; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// Problems starts from this point.
// Create a Gdiplus bitmap, and copy the content of CImage in bitmap, then write the bitmap on the screen. Gdiplus::Bitmap bmp(image.GetWidth(), image.GetHeight(), image.GetPitch(), PixelFormat32bppARGB, static\_cast(image.GetBits())); Gdiplus::Graphics graphics(pDC->GetSafeHdc()); graphics.DrawImage(&bmp, Gdiplus::Rect(0, 0, width, height)); Gdiplus::GdiplusShutdown(gdiplusToken); image.ReleaseDC(); image.Destroy(); cairo\_surface\_flush(surface); cairo\_destroy(cr); cairo\_surface\_destroy(surface);
}
Can I first say you have no error checking at all in that code ... really bad programming practice cairo_win32_surface_get_dc can fail and return NULL ... read the manual. Why might there not be a win32 surface, well because you have to set a #define CAIRO_HAS_WIN32_SURFACE 1 in the cairo library .... again in the manual. You code is totally reliant on srcHDC being valid ... Yet inexplicably you don't check it. Secondly you probably want an alpha channel on the CIMage .. the create should be CreateEx
CImage image;
image.CreateEx(width, height, 32, BI_RGB, 0, 0);Thirdly read TransparentBlt detail and if we do the Alpha channel it will then copy the source alpha onto the destination alpha ... is that Ok? If not you have to use AlphaBlend function. Fourth check GDIPlus I seem to remember it had issues with Alpha channels. Final comment is you seem to be making life difficult for yourself using 3 different systems for reasons that aren't clear. You are moving bitmap data around between systems for no real reason what you want can be done in any of the 3 systems and even natively on the Win32 API. You are even initializing the GDI plus system with a draw process ... like seriously please don't do it are you really hell bent on making the draw as slow as possible. Start the GDIPlus with the window or program and close it when done but not in a draw process ever.
In vino veritas
-
Can I first say you have no error checking at all in that code ... really bad programming practice cairo_win32_surface_get_dc can fail and return NULL ... read the manual. Why might there not be a win32 surface, well because you have to set a #define CAIRO_HAS_WIN32_SURFACE 1 in the cairo library .... again in the manual. You code is totally reliant on srcHDC being valid ... Yet inexplicably you don't check it. Secondly you probably want an alpha channel on the CIMage .. the create should be CreateEx
CImage image;
image.CreateEx(width, height, 32, BI_RGB, 0, 0);Thirdly read TransparentBlt detail and if we do the Alpha channel it will then copy the source alpha onto the destination alpha ... is that Ok? If not you have to use AlphaBlend function. Fourth check GDIPlus I seem to remember it had issues with Alpha channels. Final comment is you seem to be making life difficult for yourself using 3 different systems for reasons that aren't clear. You are moving bitmap data around between systems for no real reason what you want can be done in any of the 3 systems and even natively on the Win32 API. You are even initializing the GDI plus system with a draw process ... like seriously please don't do it are you really hell bent on making the draw as slow as possible. Start the GDIPlus with the window or program and close it when done but not in a draw process ever.
In vino veritas
Actually the problem was related to the way of copying from srcHDC to ImageHDC. I have done like this:
HDC svgDC = cairo_win32_surface_get_dc(surface);
image.Create(width, height, 32);
image.SetHasAlphaChannel(TRUE);
HDC imageHDC = image.GetDC();
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(imageHDC, 0, 0, width, height, svgDC, 0, 0, width, height, blend);image.ReleaseDC();
Best regards!