0

I have a function which captures an image of a specified window handle and then saves the image to a png file. I'm using gdi32.

This works fine, but for a window which has transparency (example: typical fancy game launcher), the transparent areas will be green (or pink depending on TernaryRasterOperations).

Here's the function which does the capture:

private static Image CaptureWindow(IntPtr handle) {
    IntPtr hdc = GetWindowDC(handle);
    RECT winRect = new RECT();

    if (GetWindowRect(handle, out winRect)) {
        Size winSize = new Size(winRect.Right - winRect.Left, winRect.Bottom - winRect.Top);
        IntPtr hdcDest = CreateCompatibleDC(hdc);
        IntPtr hBitmap = CreateCompatibleBitmap(hdc, winSize.Width, winSize.Height);
        IntPtr hOld = SelectObject(hdcDest, hBitmap);

        //if (TransparentBlt(hdcDest, 0, 0, winSize.Width, winSize.Height, hdc, 0, 0, winSize.Width, winSize.Height, ColorToUint(Color.Green))) {
        if (BitBlt(hdcDest, 0, 0, winSize.Width, winSize.Height, hdc, 0, 0, TernaryRasterOperations.SRCCOPY)) {
            SelectObject(hdcDest, hOld);
            DeleteDC(hdcDest);
            ReleaseDC(handle, hdc);
            Image img = System.Drawing.Image.FromHbitmap(hBitmap);
            DeleteObject(hBitmap);
            return img;
        }
    }
    return null;
}

I tried both BitBlt and TransparentBlt (Msimg32).

When saving the image, I've tried:

img.Save("file.png", ImageFormat.Png);

~

img = img.Clone(new Rectangle(new Point(0, 0), img.Size), PixelFormat.Format32bppArgb);
img.Save("file.png", ImageFormat.Png);

~

img.MakeTransparent(Color.Green);
img.Save("file.png", ImageFormat.Png);

I also tried saving using a filestream as suggested somewhere, but all these methods result in the same green being applied to transparent areas.

Sakuya
  • 660
  • 5
  • 23
  • Use `GetWindowDC(0)` instead of `GetWindowDC(handle)` This way you get the desktop dc, what is actually shown on desktop, instead of window dc. You will need `GetWindowRect(handle)`, supply `rect.left` and `rect.top` in to `BitBlt` – Barmak Shemirani Mar 06 '19 at 22:51

1 Answers1

0

Transparent windows do not use the alpha channel, instead they use Regions to inform the OS which areas of the top-level window are considered to be part of the window. Regions are boolean at the pixel level; in other words, there's no partial transparency.

I think you'll need to use GetWindowRgn to get the region data. From there you can try calling PtInRegion to see if a particular pixel ought to be transparent or not. If that's too slow then it may be necessary to draw the entire region to an off-screen bitmap so you can grab the raw pixel data for faster access.

RogerN
  • 3,761
  • 11
  • 18