繁体   English   中英

DrawIconEx 和 GetDIBits 的奇怪行为,alpha 为零

[英]Strange behavior with DrawIconEx and GetDIBits, with alpha as zero

我正在使用此代码来捕获屏幕 + cursor:

new System.Security.Permissions.UIPermission(System.Security.Permissions.UIPermissionWindow.AllWindows).Demand();

var success = Native.BitBlt(_compatibleDeviceContext, 0, 0, Width, Height, _windowDeviceContext, Left, Top, Native.CopyPixelOperation.SourceCopy | Native.CopyPixelOperation.CaptureBlt);

if (!success)
    return FrameCount;

try
{
    var cursorInfo = new Native.CursorInfo();
    cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);

    if (Native.GetCursorInfo(out cursorInfo))
    {
        if (cursorInfo.flags == Native.CursorShowing)
        {
            var hicon = Native.CopyIcon(cursorInfo.hCursor);

            if (hicon != IntPtr.Zero)
            {
                if (Native.GetIconInfo(hicon, out var iconInfo))
                {
                    frame.CursorX = cursorInfo.ptScreenPos.X - Left;
                    frame.CursorY = cursorInfo.ptScreenPos.Y - Top;

                    //if (frame.CursorX > 0 && frame.CursorY > 0)
                    Native.DrawIconEx(_compatibleDeviceContext, frame.CursorX - iconInfo.xHotspot, frame.CursorY - iconInfo.yHotspot, cursorInfo.hCursor, 0, 0, 0, IntPtr.Zero, 0x0003);
                 }

                 Native.DeleteObject(iconInfo.hbmColor);
                 Native.DeleteObject(iconInfo.hbmMask);
             }

             Native.DestroyIcon(hicon);
        }

        Native.DeleteObject(cursorInfo.hCursor);
    }
}
catch (Exception)
{
    //LogWriter.Log(e, "Impossible to get the cursor");
}

frame.DataLength = _byteLength;
frame.Data = new byte[_byteLength];

//If saving to disk as bitmap, it works.
//System.Drawing.Image.FromHbitmap(_compatibleBitmap).Save(frame.Path);

//If getting the image as pixel array, the square where the cursor is located is all transparent.
Native.GetDIBits(_windowDeviceContext, _compatibleBitmap, 0, (uint)Height, frame.Data, ref _infoHeader, Native.DibColorMode.DibRgbColors);

由于某种原因,当 cursor 是 I 型光束(文本光标)时,它应该位于的图像区域全是透明的。 RGB 信息在那里,但 alpha 位是0 错误的 正确的
(右侧图像是手动将所有像素 alpha 位设置为 255 后帧的外观)。

如果 cursor 是箭头,则工作正常。

但是如果我从手柄中得到Bitmap然后保存到磁盘,图像没有透明孔,正如预期的那样。

这是怎么回事? DrawIconEx还是FromHbitmap

也许FromHbitmap总是将所有像素的 alpha 设置为 255? 也许GetDiBits以不同的方式合并两个图像(屏幕截图 + 光标)?

编辑

作为快速修复,我知道我可以检测 cursor 是否为 I-Beam(蒙版单色类型)并在保存像素阵列的同时手动修复它。

//Set to fix all alpha bits back to 255.
frame.RemoveAnyTransparency = iconInfo.hbmMask != IntPtr.Zero; 

和:

if (frame.RemoveAnyTransparency)
    for (var i = 3; i < _byteLength; i += 4)
        frame.Data[i] = 255;

好吧,我怀疑这是一个特例。 因为查了很多资料,没有找到类似的案例。

但是有两种很好的方法来处理这种情况。

  • 通过设置biBitCount = 24避免 alpha 通道
  • 将 cursor 数据复制到 DIBSection 的 bitmap 数据中,使用 alpha 通道字节进行混合(alpha = 255)。

    创建一个设备上下文并将 select 将 DIBSection 放入其中。

    使用BitBlt()从新设备上下文复制到绘制设备上下文。

    参考: 如何绘制 32 位 alpha 通道位图?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM