Haskell中的屏幕截图?

问题描述:

是否有可能在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

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

你应该可以用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程序员会感谢一个简单的截图方法。

你也可以做到这一点与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