You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# .NET 6 WinForm如何实现1440P屏幕60FPS快速截图

优化C# WinForm .NET6下1440P屏幕截图速度方案

当前CopyFromScreen的性能瓶颈来自GDI+的封装开销,要达到接近视频设备捕获的速度,需要利用底层系统API或硬件加速机制,以下是几种可行方案:

方案1:BitBlt替代CopyFromScreen

BitBlt是底层GDI函数,跳过GDI+的部分封装逻辑,能将截图耗时压缩到10-15ms左右。

实现代码

using System.Runtime.InteropServices;
using System.Drawing.Imaging;

public class FastScreenshotHelper
{
    [DllImport("gdi32.dll")]
    private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);

    [DllImport("user32.dll")]
    private static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    public Bitmap CaptureScreenWithBitBlt()
    {
        var screenBounds = Screen.PrimaryScreen.Bounds;
        var bitmap = new Bitmap(screenBounds.Width, screenBounds.Height, PixelFormat.Format32bppArgb);

        using (var gDest = Graphics.FromImage(bitmap))
        {
            var hdcDest = gDest.GetHdc();
            var hdcSrc = GetDC(IntPtr.Zero); // 获取全屏设备上下文

            // SRCCOPY:直接复制源区域像素到目标
            BitBlt(hdcDest, 0, 0, screenBounds.Width, screenBounds.Height, hdcSrc, 0, 0, 0x00CC0020);

            ReleaseDC(IntPtr.Zero, hdcSrc);
            gDest.ReleaseHdc(hdcDest);
        }

        return bitmap;
    }
}

方案2:Windows Graphics Capture API(推荐,硬件加速)

这是Win10 1903+支持的系统级API,直接从GPU显存捕获帧,耗时可低至1-5ms,接近视频设备捕获速度。需要依赖Microsoft.Windows.SDK.Contracts和SharpDX.Direct3D11 NuGet包。

实现代码

using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Graphics.DirectX.Direct3D11;
using System.Runtime.InteropServices.WindowsRuntime;
using Emgu.CV;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System.Drawing.Imaging;

public class HardwareAcceleratedCapture
{
    private GraphicsCaptureItem _captureItem;
    private Direct3D11CaptureFramePool _framePool;
    private GraphicsCaptureSession _session;
    private Mat _latestFrame;

    // 初始化捕获(需在UI线程调用,首次运行会弹出权限提示)
    public async Task Initialize()
    {
        // 获取主屏幕作为捕获目标
        var display = DisplayMonitor.GetFromDisplayName(Screen.PrimaryScreen.DeviceName);
        _captureItem = GraphicsCaptureItem.CreateFromDisplayMonitor(display);

        // 创建Direct3D硬件设备
        var d3dDevice = CreateD3DDevice();
        _framePool = Direct3D11CaptureFramePool.Create(
            d3dDevice,
            DirectXPixelFormat.B8G8R8A8UIntNormalized,
            2, // 缓存2帧避免丢帧
            _captureItem.Size);

        _session = _framePool.CreateCaptureSession(_captureItem);
        _framePool.FrameArrived += OnFrameArrived;
        _session.StartCapture();
    }

    private static IDirect3DDevice CreateD3DDevice()
    {
        var device = new Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport);
        return device.As<IDirect3DDevice>();
    }

    // 帧到达时处理,直接转成EmguCV Mat
    private void OnFrameArrived(Direct3D11CaptureFramePool sender, object args)
    {
        using (var frame = sender.TryGetNextFrame())
        {
            if (frame == null) return;

            using (var surface = frame.Surface)
            {
                var dxgiSurface = surface.As<Surface>();
                var bitmap = new Bitmap(frame.ContentSize.Width, frame.ContentSize.Height, PixelFormat.Format32bppArgb);
                var rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);

                // 锁定Bitmap内存,直接从显存拷贝数据
                var bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
                dxgiSurface.MapToMemory(out var pointer, out var pitch);
                System.Buffer.MemoryCopy(pointer, bitmapData.Scan0, bitmapData.Stride * bitmap.Height, bitmapData.Stride * bitmap.Height);
                dxgiSurface.Unmap();
                bitmap.UnlockBits(bitmapData);

                // 转成Mat供机器学习检测使用
                _latestFrame = BitmapConverter.ToMat(bitmap);
            }
        }
    }

    // 获取最新捕获帧
    public Mat GetLatestFrame()
    {
        return _latestFrame?.Clone();
    }

    // 停止捕获,释放资源
    public void StopCapture()
    {
        _session?.StopCapture();
        _framePool?.Dispose();
        _session?.Dispose();
    }
}

方案3:跳过Bitmap中间转换(进一步优化)

如果你的检测逻辑直接使用EmguCV Mat,可以修改OnFrameArrived方法,直接将显存数据写入Mat,避免Bitmap的创建和转换步骤,进一步减少耗时:

private void OnFrameArrived(Direct3D11CaptureFramePool sender, object args)
{
    using (var frame = sender.TryGetNextFrame())
    {
        if (frame == null) return;

        using (var surface = frame.Surface)
        {
            var dxgiSurface = surface.As<Surface>();
            var width = frame.ContentSize.Width;
            var height = frame.ContentSize.Height;

            // 创建对应尺寸的Mat
            var mat = new Mat(height, width, Emgu.CV.CvEnum.DepthType.Cv8U, 4);

            // 直接从显存拷贝到Mat内存
            dxgiSurface.MapToMemory(out var pointer, out var pitch);
            System.Buffer.MemoryCopy(pointer, mat.DataPointer, mat.Step * mat.Rows, mat.Step * mat.Rows);
            dxgiSurface.Unmap();

            _latestFrame = mat;
        }
    }
}

性能对比

方案耗时范围
CopyFromScreen30ms+
BitBlt10-15ms
Windows Graphics Capture1-5ms

注意事项

  • Windows Graphics Capture仅支持Win10 1903及以上版本,若需兼容旧系统,优先选择BitBlt方案。
  • 使用Direct3D相关API时,务必在程序退出时调用StopCapture释放资源,避免内存泄漏。
  • 首次使用Windows Graphics Capture会触发系统权限弹窗,需用户允许屏幕捕获权限。

内容的提问来源于stack exchange,提问作者coolshrimp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 19:01:17