【发布时间】:2019-11-09 09:50:45
【问题描述】:
我需要更改屏幕捕获代码以获取像素数组而不是位图。
我把代码改成这样:
BitBlt > Image.FromHbitmap(pointer) > LockBits > pixel array
但是,我正在检查是否有可能削减一些中间人,并有这样的东西:
BitBlt > Marshal.Copy > pixel array
甚至:
WinApi method that gets the screen region as a pixel array
到目前为止,我尝试使用此代码,但没有成功:
public static byte[] CaptureAsArray(Size size, int positionX, int positionY)
{
var hDesk = GetDesktopWindow();
var hSrce = GetWindowDC(hDesk);
var hDest = CreateCompatibleDC(hSrce);
var hBmp = CreateCompatibleBitmap(hSrce, (int)size.Width, (int)size.Height);
var hOldBmp = SelectObject(hDest, hBmp);
try
{
new System.Security.Permissions.UIPermission(System.Security.Permissions.UIPermissionWindow.AllWindows).Demand();
var b = BitBlt(hDest, 0, 0, (int)size.Width, (int)size.Height, hSrce, positionX, positionY, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
var length = 4 * (int)size.Width * (int)size.Height;
var bytes = new byte[length];
Marshal.Copy(hBmp, bytes, 0, length);
//return b ? Image.FromHbitmap(hBmp) : null;
return bytes;
}
finally
{
SelectObject(hDest, hOldBmp);
DeleteObject(hBmp);
DeleteDC(hDest);
ReleaseDC(hDesk, hSrce);
}
return null;
}
当我踩到Marshal.Copy 时,这段代码给了我一个System.AccessViolationException。
在使用 BitBlt 或类似的屏幕捕获方法时,有没有更有效的方法将屏幕像素作为字节数组获取?
编辑:
正如在 here 中发现的那样,并且按照 CodyGray 的建议,我应该使用
var b = Native.BitBlt(_compatibleDeviceContext, 0, 0, Width, Height, _windowDeviceContext, Left, Top, Native.CopyPixelOperation.SourceCopy | Native.CopyPixelOperation.CaptureBlt);
var bi = new Native.BITMAPINFOHEADER();
bi.biSize = (uint)Marshal.SizeOf(bi);
bi.biBitCount = 32;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
bi.biCompression = 0;
bi.biHeight = Height;
bi.biWidth = Width;
bi.biPlanes = 1;
var data = new byte[4 * Width * Height];
Native.GetDIBits(_windowDeviceContext, _compatibleBitmap, 0, (uint)Height, data, ref bi, Native.DIB_Color_Mode.DIB_RGB_COLORS);
我的data 数组包含屏幕截图的所有像素。
现在,我将测试是否有任何性能改进。
【问题讨论】:
-
你使用
hBmp(本质上是Bitmap.GetHBitmap)就好像它是BitmapData.Scan0。这些指针是不同的。BitmapData到底有什么问题?如果您想为 GDI+ 使用一些托管包装器,那是您的最佳选择。它最终会出现在您无论如何都会使用的相同外部调用中。 -
确实,它们是不同的指针。我只是想知道是否可以减少捕获延迟。
-
您不会获得太多收益,因为
LockBits是在 gdiplus.dll 中对GdipBitmapLockBits的简单调用,它填充了BitmapData。你也会这样做。最大的性能损失在Marshal.Copy,恕我直言。 -
你可以学习一个好的截屏应用的代码:github.com/ShareX/ShareX
-
@GyörgyKőszeg 我在另一个网站上找到了我想要的解决方案。他们基本上使用
GetDIBits来获取数组。我要测试一下。
标签: c# winapi screen-capture bitblt