我正在使用此代码来捕获屏幕+光标:
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);
由于某种原因,当光标是工字梁(文本光标)时,它应该位于的图像区域全是透明的。RGB 信息在那里,但 alpha 位是0
.
(右图是手动将所有像素 alpha 位设置为 255 后帧的样子)。
如果光标是箭头,则正常工作。
但是,如果我Bitmap
从句柄中获取然后保存到磁盘,则图像没有透明孔,正如预期的那样。
这是怎么回事?是 withDrawIconEx
还是 with FromHbitmap
?
也许FromHbitmap
总是将所有像素的 alpha 设置为 255?也许GetDiBits
以不同的方式合并两个图像(屏幕截图+光标)?
编辑
作为快速修复,我知道我可以检测光标是否为 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;