摘要:WPF 抓取螢幕擷圖
在 MSDN 上看到 WPF 抓取螢幕擷圖的討論,
而原討論中的程式範例有 Memory leak 的問題,
因此我做了些修改。
新增一個 WPF 專案,
並將 System.Drawing 加入參考。
using System;  // IntPtr
using System.Windows;  // SystemParameters, Int32Rect
using System.Windows.Media.Imaging;  // BitmapSource
using System.Drawing;  // Bitmap, Graphics
using System.Windows.Interop;  // Imaging
using System.Runtime.InteropServices;  // DllImport
[DllImport("gdi32.dll")]
static extern IntPtr DeleteObject(IntPtr hDc);
static BitmapSource CopyScreen()
{
    using (var screenBmp = new Bitmap((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
    {
        using (var bmpGraphics = Graphics.FromImage(screenBmp))
        {
            bmpGraphics.CopyFromScreen(0, 0, 0, 0, screenBmp.Size);
            IntPtr hBitmap = screenBmp.GetHbitmap();
            return Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(hBitmap);
        }
    }
    return bmpSource;
}
上面的例子是擷取整個主螢幕的畫面,
也可以擷取指定的螢幕範圍,修改如下:
static BitmapSource CopyScreen(int left, int top, int width, int height)
{
    BitmapSource bmpSource;
    using (var screenBmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
    {
        using (var bmpGraphics = Graphics.FromImage(screenBmp))
        {
            bmpGraphics.CopyFromScreen(left, top, 0, 0, screenBmp.Size, CopyPixelOperation.SourceCopy);
            IntPtr hBitmap = screenBmp.GetHbitmap();
            bmpSource = Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(hBitmap);
        }
    }
    return bmpSource;
}
如果你在短時間內會大量擷取螢幕畫面(如每秒 30 次),
記得每次處理完後都要呼叫 GC.Collect() 強迫 CLR 回收記憶體,
否則很快就會 Out of Memory。