Heresy 之前因為工作上的需要,有必要寫程式去抓螢幕的畫面,拿來做後續的應用,所以就針對 Windows 環境下、擷取螢幕的方法、去找了一些資料。
而這一篇文章就是參考 MSDN 上的《Ways to capture the screen》,在該文中整理了幾種在 Windows 環境下擷取螢幕的方法。這邊 Heresy 算是稍微紀錄一下。
在該文章中,基本上有下面五種方法:
-
使用 Desktop Duplication API
這個方法是使用 DXGI(DirectX Graphics Infrastructure)來做螢幕的擷取,他的說明可以參考 MSDN 上的《Desktop Duplication API》。
這個方法的效率算是相當好的!不過,他最大的缺點,在於只適用於 Windows 8 以後的作業系統,在之前的作業系統是無法使用的。
此外,雖然他可以捕捉到 OpenGL 或 DirectX 這類的 3D 程式的內容,但是如果這類的程式是在全螢幕的排外模式(exclusive mode)下運作的話,是很有可能沒辦法被擷取的。
Heresy 目前是採用這種方法來做螢幕的擷取,在網路上也有人有分享相對完整的範例程式。Heresy 是參考了 GitHub 上的「DXGICaptureSample」這個範例、把它改成函式庫的型態,有興趣的話可以參考:
-
使用 GDI
這個方法是比較老式的方法,使用 Windows GDI(graphics device interface、參考)來做螢幕的擷取,一般來說會用到 BitBlt() 這個函式(MSDN)。
這個的缺點在於他可能沒辦法捕捉到畫面中的某些東西,例如多媒體的內容。
這部分可以參考 MSDN 的《Capturing an Image》這篇文章。
-
使用 Direct 3D
由於現在的 Windows 基本上應該底層都是用 DirectX 來實作的,所以也可以使用 Direct 3D 來做截圖。
基本的概念,就是使用 GetRenderTargetData() 這個函式、來複製透過 GetRenderTarget() 取得的 rendering surface,並把他複製、儲存。
-
使用 Windows Media Video 9 Screen Codec
如果只是要一個現成的工具來擷取桌面的話,可以直接使用 Expression Encoder(官網)來做。
而如果是要寫程式的話,則是可以使用 Windows Media Video 9 Screen codec。
-
透過自己寫的驅動程式來做
在 Windows 8 以前的作業系統,微軟有提供「Mirror Driver」的架構,可以用來寫一個用來複製螢幕的驅動程式。
而從 Windows 8 開始,微軟則是提供了「Remote Display Drivers」來做同樣的事。
如果不是要抓全螢幕、而是要抓單一視窗的話,其實 Windows SDK 就有 PrintWindow() 這個 API 可以拿來用;此外,上面第二個、第三個方法,也都可以只抓單一視窗。
由於 Heresy 最後是決定使用 DXGI 來做,所以其他方法就沒研究怎麼用了。但是在網路上,大多都還是可以找到範例的!
像是 CodeProject 的《Various methods for capturing the screen》一文中,就有針對 2 – 4 的方法,做比較詳細的說明、並也有提供範例程式,如果有需要的話應該可以參考。
不過像是「Remote Display Drivers」,就好像找不到什麼資料可以參考了…
另外,其實 NVIDIA 也有 NvFBC 這種可以直接透過顯示卡驅動程式來做螢幕擷取的方法,不過很可惜地被鎖在 NVIDIA GRID 上,雖然一般新的 GeForce 卡也做得到,但是沒有 API 可以用…(GRID SDK)
此外,在 Mac OS X 的環境下,似乎因為已經都是用 OpenGL 來繪製的了,所以也可以用 OpenGL 的函式,來進行桌面的擷取。