2012-08-15 187 views
12

是否有可能在Windows環境中使用Haskell捕獲屏幕(或窗口)? (即每幾分鐘左右截圖)。如果是這樣,那麼怎麼會這樣做(再次,在哈斯克爾,Windows環境)?Haskell中的屏幕截圖?

更多信息: 我是初學者哈斯克爾。一位朋友希望通過讓我爲他的會計公司開發一些項目來削減開發成本,但他堅持認爲我使用了Haskell。他希望有一款工具可以讓他監控不同Windows XP工作站的桌面。它可能必須是客戶端/服務器類型的應用程序。他只需要監控桌面活動,因此他不需要任何已經上市的昂貴管理軟件。我篩選了大量的文檔,只是發現了wxHaskell,但在捕獲屏幕方面找不到太多東西,尤其是在Windows環境下。

+0

你是否認爲只是從Haskell調用外部程序,它需要一個截圖? – Probie 2012-08-15 03:01:25

+0

@Probie事實上,我已經考慮過在Haskell中製作客戶端和服務器,並以不同的時間間隔發送屏幕截圖。但是,這看起來非常直觀。爲什麼即使使用Haskell開始,如果只有這樣一小部分軟件實際上是Haskell。 唉,這是Haskell社區應該解決的問題。如果我們希望Haskell更加突出,我們肯定需要解決這些類型的問題。 – 2012-08-15 03:09:16

回答

17

Tikhon提到的方法是正確的。只是添加一些代碼到他上面

import Graphics.Win32.Window 
import Graphics.Win32.GDI.Bitmap 
import Graphics.Win32.GDI.HDC 
import Graphics.Win32.GDI.Graphics2D 

main = do desktop <- getDesktopWindow -- Grab the Hwnd of the desktop, GetDC 0, GetDC NULL etc all work too 
      hdc  <- getWindowDC (Just desktop) -- Get the dc handle of the desktop 
      (x,y,r,b) <- getWindowRect desktop -- Find the size of the desktop so we can know which size the destination bitmap should be 
              -- (left, top, right, bottom) 
      newDC  <- createCompatibleDC (Just hdc) -- Create a new DC to hold the copied image. It should be compatible with the source DC 
      let width = r - x -- Calculate the width 
      let height = b - y -- Calculate the Height 
      newBmp <- createCompatibleBitmap hdc width height -- Create a new Bitmap which is compatible with the newly created DC 
      selBmp <- selectBitmap newDC newBmp -- Select the Bitmap into the DC, drawing on the DC now draws on the bitmap as well 
      bitBlt newDC 0 0 width height hdc 0 0 sRCCOPY -- use SRCCOPY to copy the desktop DC into the newDC 
      createBMPFile "Foo.bmp" newBmp newDC -- Write out the new Bitmap file to Foo.bmp 
      putStrLn "Bitmap image copied" -- Some debug message 
      deleteBitmap selBmp -- Cleanup the selected bitmap 
      deleteBitmap newBmp -- Cleanup the new bitmap 
      deleteDC newDC  -- Cleanup the DC we created. 

這只是迅速把一起給出的答案,但它保存到一個名爲Foo.bmp文件的截圖。 Ps。給誰就給誰寫的Win32的圖書館,很好地完成:)

+0

看起來不錯!這一定會幫助我和Haskell一起冒險。謝謝! – 2012-08-15 22:56:23

11

你應該可以用Win32 API來做到這一點。根據What is the best way to take screenshots of a Window with C++ in Windows?,您需要獲取窗口的上下文,然後分別使用GetWindowDCBitBlt從中複製圖像。哈斯克爾的Win32 API文檔各地

來看,存在一個Graphics.Win32.Window功能getWindowDC。這將返回IO HDCGraphics.Win32.GDI.Graphics2D中有bitblt函數。該功能需要HDC以及一大堆INT s,這大概對應於C++中所需的參數。

不幸的是,我沒有一臺Windows機器,所以我不能寫實際的代碼。你必須弄清楚如何自己使用Win32 API函數,這可能有點麻煩。

當你這樣做的時候,如果你把它分解成一個庫並把它放在Hackage上 - Windows通常不會在Haskell的土地上獲得太多的愛(如我自己展示的:P),所以我肯定其他Windows程序員會感謝一個簡單的截圖方法。

12

你也可以做到這一點與GTK一個跨平臺的方式。

與C:Taking a screenshot with C/GTK做法沒有多大區別。

{-# LANGUAGE OverloadedStrings #-} 

import Graphics.UI.Gtk 
import System.Environment 
import Data.Text as T 

main :: IO() 
main = do 
    [fileName] <- getArgs 
    _ <- initGUI 
    Just screen <- screenGetDefault 
    window <- screenGetRootWindow screen 
    size <- drawableGetSize window 
    origin <- drawWindowGetOrigin window 
    Just pxbuf <- 
     pixbufGetFromDrawable 
      window 
      ((uncurry . uncurry Rectangle) origin size) 
    pixbufSave pxbuf fileName "png" ([] :: [(T.Text, T.Text)]) 
+0

這種方法看起來非常乾淨和直接。我一定記住它。雖然它會非常相似,但我想在Haskell中看到一些例子,因爲我仍然是初學者。 – 2012-08-15 22:58:40

+0

@ M.Ferguson,你走吧。結果有點不同:我沒有找到相當於'gdk_get_default_root_window',所以需要額外調用'screenGetDefault'。 – Rotsor 2012-08-16 16:56:33

+0

@Rotsor'gdk_get_default_root_window'包裝着'Graphics.UI.Gtk.Gdk.DrawWindow.drawWindowGetDefaultRootWindow',不是最簡單的東西,雖然 – 2012-08-18 10:23:36