c# - 将屏幕像素作为字节数组获取
问题描述
我需要更改屏幕捕获代码以获取像素数组而不是位图。
我将代码更改为:
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;
}
这段代码给了我一段System.AccessViolationException
时间Marshal.Copy
。
在使用 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
数组包含屏幕截图的所有像素。现在,我将测试是否有任何性能改进。
解决方案
是的,您不能只是BITMAP
通过HBITMAP
(由CreateCompatibleBitmap
)开始访问对象的原始位。HBITMAP
顾名思义,只是一个把手。它不是经典“C”意义上的指针,它指向数组的开头。句柄就像间接指针。
GetDIBits
是从可以迭代的位图中获取原始的、与设备无关的像素数组的适当解决方案。但是您仍然需要首先使用获取屏幕位图的代码。本质上,你想要这样的东西。当然,您需要将其翻译成 C#,但这应该不难,因为您已经知道如何调用 WinAPI 函数。
请注意,您不需要调用GetDesktopWindow
或GetWindowDC
。只需NULL
作为句柄传递给GetDC
; 它具有返回屏幕 DC 的相同效果,然后您可以使用它来创建兼容的位图。一般来说,您几乎不应该调用GetDesktopWindow
.
推荐阅读
- puppeteer - 如何将 Chrome 添加到容器以克服 circleCI 中的错误“无法启动 chrome”
- react-native - VS Code 实时分享反应原生?
- c++ - 为什么使用多重继承时我的 Hippomock 期望失败
- python - AttributeError:模块“tensorflow”没有属性“assign”
- tensorflow - LSTM 层输出大小与 KERAS 中的隐藏状态大小
- php - foreach 中未定义的属性,除非 print_r'd
- php - .htaccess FilesMatch 以阻止 php 执行名称包含大写字母的 php 文件
- cassandra - 增加 roles_validity_in_ms 和 permissions_validity_in_ms 的影响
- ios - 在 Xcode 11 中通过 Fastlane 构建 SPM 包不起作用
- c# - OpenXML 将行追加到 Word 中的现有表