首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 螢幕截圖三種方案深度解析 (二)

     編輯:關於C語言

承上篇,前兩種方案 (GDI BitBlt、PrintWindow) 在 WPF Popup 視窗上均失效:前者截到背景,後者 WPF 區域呈現黑塊。根因在於 WPF 使用 DirectX 渲染,繞過 GDI 裝置內容 (DC)。本文探討第三種方案:模擬 PrintScreen 鍵並從剪貼簿取圖。

方案三:模擬鍵盤事件 + 剪貼簿

const uint KEYEVENTF_EXTENDEDKEY = 0x1;
const uint KEYEVENTF_KEYUP = 0x2;
const byte VK_SNAPSHOT = 0x2C;

Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero);
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero);

// 給系統時間將圖片放入剪貼簿
Thread.Sleep(100);

IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
    using (var screenBmp = (Bitmap)data.GetData(DataFormats.Bitmap))
    using (var outputBmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb))
    using (var g = Graphics.FromImage(outputBmp))
    {
        g.DrawImage(screenBmp,
            new Rectangle(0, 0, rect.Width, rect.Height),
            rect.X, rect.Y, rect.Width, rect.Height,
            GraphicsUnit.Pixel);
        outputBmp.Save(path, ImageFormat.Bmp);
    }
}

關鍵問題與待解決項

  1. 剪貼簿污染:覆蓋使用者原有剪貼簿內容。需在截圖前備份、事後還原 (含多種格式)。
  2. 時序競態:Thread.Sleep 不可靠。需輪詢剪貼簿或使用 Clipboard.GetDataObject() 非同步模式。
  3. 多螢幕/高 DPI:PrintScreen 捕捉整個虛擬螢幕,需正確計算目標視窗在虛擬螢幕中的座標。
  4. WPF 專用 API:RenderTargetBitmap 可直接渲染 WPF 視覺樹,但無法捕捉非 WPF 視窗 (如 Win32 子視窗、硬體加速視訊)。

替代方案展望

  • DirectX Desktop Duplication API (Windows 8+):高效能、無剪貼簿副作用、支援硬體加速內容,但需 C++/COM 互操作,複雜度高。
  • Magnification API:原為螢幕放大鏡設計,可捕捉分層視窗內容,含 WPF。
  • WPF 內部截圖:若僅需截取自家 WPF 視窗,RenderTargetBitmap 是最佳選擇。

實務建議

若專案允許依賴第三方庫,推薦 ScreenToGif 核心截圖邏輯 (採用 Desktop Duplication + Magnification 回退)。若必須自行實作,優先嘗試 RenderTargetBitmap (純 WPF) 或 Magnification API (混合 HWND),將模擬鍵盤方案作為最後回退。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved