Transparency on white background bitmap C++ winapi - c++

well i have a question about transparency in a bitmap file which i want to save as png file, at the moment i take a screenshot of the cursor in the system and save it as png, this work fine whit arrow, hand and other cursors but in the moment of use cursors like I-beam or "not" cursor this have a problem, the explanation is that each cursor have a mask and a color bitmap which combine and result in a transparent cursor but I-beam and others no have color bitmap, them have only mask that contains the color and mask in the same bitmap, i refer this post: C# - Capturing the Mouse cursor image well they use C# but the idea is the same.
in my code i use C++ and i manage to create a cursor but with white background color, i don't know how to convert it in transparent color, in the post i refer use a function MakeTransparent, any idea? thanks for the help :D
CURSORINFO cursor;
ICONINFO cursorIconInfo;
HICON cursorIcon;
cursor.cbSize=sizeof(CURSORINFO);
GetCursorInfo(&cursor);
GetIconInfo(cursor.hCursor,&cursorIconInfo);
//cursorIcon=CopyIcon(cursor.hCursor);
//GetIconInfo(LoadCursor(NULL,IDC_ARROW),&cursorIconInfo);
//cursorIcon=CreateIconIndirect(&cursorIconInfo);
CxImage* imag=new CxImage();
/*imag->CreateFromHICON(cursorIcon);
imag->Save("cursor.png",CXIMAGE_FORMAT_PNG);*/
BITMAP bm;
//CImage* imag=new CImage();
GetObject(cursorIconInfo.hbmMask,sizeof(BITMAP),&bm);
if(bm.bmHeight == bm.bmWidth*2){
HDC screendc=CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
HDC cursormaskDC=CreateCompatibleDC(screendc);
HDC cursorfinalDC=CreateCompatibleDC(screendc);
HBITMAP cursormask=CreateCompatibleBitmap(screendc,bm.bmWidth,bm.bmWidth);
HBITMAP cursorfinal=CreateCompatibleBitmap(screendc,bm.bmWidth,bm.bmWidth);
SelectObject(cursormaskDC,cursorIconInfo.hbmMask);
SelectObject(cursorfinalDC,cursorfinal);
BitBlt(cursorfinalDC,0,0,bm.bmWidth,bm.bmWidth,cursormaskDC,0,bm.bmWidth,SRCCOPY);
BitBlt(cursorfinalDC,0,0,bm.bmWidth,bm.bmWidth,cursormaskDC,0,0,SRCINVERT);
/*cursorIconInfo.hbmColor=cursorcolor;
cursorIconInfo.hbmMask=cursormask;
cursorIcon=CreateIconIndirect(&cursorIconInfo);
imag->CreateFromHICON(cursorIcon);
imag->Save("cursorPrub.png",CXIMAGE_FORMAT_PNG);*/
imag->CreateFromHBITMAP(cursorfinal);
imag->Save("cursor.png",CXIMAGE_FORMAT_PNG);
DeleteObject(cursorIconInfo.hbmMask);
DeleteObject(cursorIconInfo.hbmColor);
DestroyIcon(cursorIcon);
imag->Destroy();
return;
}

Use GDIPlus. It work correct with alpha. Gdi works incorrect with alpha sometime.

Related

Capture desktop screenshot as vector image and place into clipboard using MFC

I am developing an MFC application, where I need to capture the desktop and save as a vector image.
I can capture screen shot as .BMP and write to clipboard with following code.
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HDC hDesktopDC = GetDC(NULL);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC,
nScreenWidth, nScreenHeight);
HGDIOBJ old_obj = SelectObject(hCaptureDC,hCaptureBitmap);
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,
hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hCaptureBitmap);
CloseClipboard();
// clean up
SelectObject(hCaptureDC, old_obj);
DeleteDC(hCaptureDC);
ReleaseDC(NULL, hDesktopDC);
DeleteObject(hCaptureBitmap);
But I am looking something similar code which would allow me to capture screenshot as vector image and place into clipboard; so, I can read as EMF from clipboard.
I tried searching for MFC functions to convert raster images to vector images from clipboard, but I have not found anything useful.
You can't. A screenshot gathers pixel data only. All information on how those pixels were generated (which is essentially what an EMF would store) is lost. It's not possible to recover the GDI calls issued to construct the final image.
Even if that were possible, EMF wouldn't be capable of representing rendering information for image data that is not produced by the GDI (e.g. Qt applications with an OpenGL/Direct2D rasterizer, WPF applications, or UWP applications).

Screen capture to Direct2D compatible bitmap

I need to capture the screen of a windows given its HWND handle and store the capture in a ID2D1Bitmap object in order to draw this bitmap by means of my render target.
How can I achive this result?
Direct2D doesn't provide such functionality.
A possible way to go is if you first capture the screen via GDI (1) and then create a ID2D1Bitmap from the returned bitmap handle (2).
Getting a HBITMAP - Check this answer: https://stackoverflow.com/a/5164267/3962893. You need the part till the HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height); The hbDesktop variable will contain a handle to the screen captured bitmap.
Creating an ID2D1Bitmap from a HBITMAP - check this answer: https://stackoverflow.com/a/27500938/3962893. It copies an icon to a ID2D1Bitmap, but the workflow is identical. Except:
hIcon := SendMessage(Handle, WM_GETICON, ICON_BIG, 0);
....
wicFactory.CreateBitmapFromHICON(hIcon, wicBitmap);
that you have to change to:
wicFactory.CreateBitmapFromHBITMAP(hbDesktop, wicBitmap);

GDI - How to create and fill bitmap?

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
:)

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.

Unit testing of control drawing in GDI

I have a control written in C++ using WinAPI and I would like to automatically test that it is being drawn properly. I can either compare the drawn image with saved reference images or simply test that specific pixels have specific color. I have both types implemented.
The problem is that the tests now also run every night on a virtual machine which for some reason has only 16bit color depth. This causes the colors to be slightly off. I have tried to come up with colors that wouldn't be changed when drawn in 16bit color depth, but the rounding scheme seems to be rather complicated and I need the tests to be functional in both 32b an 16b color depths.
Another idea was to create an offscreen bitmap that would always have 32b color depth. It would have the benefit that the tests would use the same environment every time,but I couldn't get that to work. How can I create a 32b HBITMAP and HDC regardless of the screen color depth? Or do you have any other tips how to solve the general problem?
Thanks
How can I create a 32b HBITMAP and HDC
regardless of the screen color depth?
it's simple:
BITMAPINFO bmp_info = {};
bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmp_info.bmiHeader.biWidth = width;
bmp_info.bmiHeader.biHeight = height;
bmp_info.bmiHeader.biPlanes = 1;
bmp_info.bmiHeader.biBitCount = 32;
bmp_info.bmiHeader.biCompression = BI_RGB;
HDC mem_dc = CreateCompatibleDC(0);
void *dummy;
HBITMAP bitmap_handle = CreateDIBSection(mem_dc, &bmp_info, DIB_RGB_COLORS, &dummy, NULL, 0);
SelectObject(mem_dc, bitmap_handle));
now draw your button over this DC. Remember to check for errors and to release resources.
Or alternatively, automatically convert your button reference view to actual desktop mode:
HWND desktop = GetDesktopWindow();
HDC desktop_dc = GetDC(desktop);
HDC mem_dc = CreateCompatibleDC(desktop_dc);
RECT rect;
GetClientRect(desktop, &rect);
HBITMAP bitmap_handle = CreateCompatibleBitmap(desktop_dc, rect.right - rect.left, rect.bottom - rect.top);
SelectObject(mem_dc, bitmap_handle);
and now BitBlt your preloaded image over mem_dc. It will be automatically converted to current desktop color mode
I've done GDI unit testing by drawing into a WMF (now EMF) file. It did replicate the resolution and DPI of a source (and the later destination) device, but I don't recall if color depth was a "sticky" attribute. Even if it was, since the fileformat allows you to capture/replay the GDI sequence, you might have a more accurate unit test in the end anyways. We'd interpret the WMF file to make sure we generated what we thought we should.
CreateEnhMetaFile is a starting point.
What about using GDI+ to create the offscreen bitmap, and then drawing to it with GDI - something like this:
int width=64; // or whatever you need
int height=100;
int stride = width*4;
BYTE buffer[stride*height];
Gdiplus::Bitmap bitmap(width, height, stride, PixelFormat32bppARGB, buffer);
Gdiplus::Graphics g (&bitmap);
HDC dc = g.GetHDC();
// drawing code, using WinAPI, to draw to dc
g.ReleaseHDC();
// Now compare the contents of your buffer
More about gdi / gdi+ interop here: http://support.microsoft.com/kb/311221
Change your test to pass if comparison against the 32 bit image or against the 16 bit image is OK. Capture both 32 bit versions and 16 bit versions (running virtual). This is really quick and easy to implement.
You should already have an automatic way to capture the reference images for a known good version of the code. If you don't, do that now, as it will save you time later when you make small changes to the appearance of the control. You now have the reference for regression testing.
Either create a 32bpp offscreen surface like you said, or perform the exact same operation with your comparison reference image so you are testing both at the same bpp. In other words don't do your own rounding; let the GDI system do the same rounding to both surfaces.