2012-08-15 18 views
12

¿Es posible capturar la pantalla (o una ventana) usando Haskell en un entorno Windows? (es decir, tomar una captura de pantalla cada pocos minutos más o menos). Si es así, ¿cómo haría uno para hacer esto (nuevamente, en Haskell, para un entorno Windows)?Captura de pantalla en Haskell?

Más información: Soy un principiante de Haskell. Un amigo quiere reducir los costos de desarrollo al hacer que prepare algunos programas para su firma de contabilidad, pero insiste en que use Haskell. Él quiere una herramienta que le permita monitorear los escritorios de diferentes estaciones de trabajo de Windows XP. Es probable que tenga que ser una aplicación de tipo cliente/servidor. Solo necesita monitorear la actividad del escritorio, por lo que no quiere ninguno de los costosos software de administración que ya están en el mercado. Revisé mucha documentación y solo llegué a encontrar a wxHaskell, pero no pude encontrar mucho para capturar la pantalla, especialmente para entornos Windows.

+0

¿Ha considerado simplemente llamar a un programa externo de Haskell que toma una captura de pantalla? – Probie

+0

@Probie De hecho, he considerado simplemente hacer el cliente y el servidor en Haskell, y enviar las capturas de pantalla en diferentes intervalos. PERO, esto parece tan contraintuitivo. ¿Por qué molestarse en usar Haskell para empezar si solo una parte tan pequeña del software es realmente Haskell? Por desgracia, es algo que la comunidad Haskell debería abordar. Si queremos que Haskell sea más prominente, definitivamente necesitaremos resolver este tipo de problemas. –

Respuesta

17

El Método Tikhon mencionado es correcto. Sólo para añadir algo de código a la respuesta que dio anteriormente

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. 

Esto se acaba rápidamente armó, pero guarda una captura de pantalla en un archivo denominado foo.bmp. Ps. A quienquiera que haya escrito la Biblioteca Win32, muy bien hecho :)

+0

¡Se ve bien! Esto definitivamente me ayudará en mis aventuras con Haskell. ¡Gracias! –

11

Debería poder hacer esto con la API de Win32. Basado en What is the best way to take screenshots of a Window with C++ in Windows?, necesita obtener el contexto de la ventana y luego copiar la imagen desde GetWindowDC y BitBlt respectivamente.

Examinando la documentación de la API Has32 de Haskell, existe una función de getWindowDC en Graphics.Win32.Window. Esto devuelve un IO HDC. Hay una función bitblt en Graphics.Win32.GDI.Graphics2D. Esta función toma un HDC junto con un grupo de INT s que presumiblemente corresponden a los argumentos que toma en C++.

Lamentablemente, no tengo una máquina con Windows a mano, así que no puedo escribir el código real. Tendrá que averiguar cómo usar las funciones de API de Win32 usted mismo, lo que puede ser un poco molesto.

Cuando lo haga, sería genial si tuviera en cuenta una biblioteca y lo subiera a Hackage - Windows normalmente no recibe mucho amor en Haskell Land (como yo mismo muestro: P), entonces estoy Seguro que otros programadores de Windows estarían agradecidos por una manera fácil de tomar capturas de pantalla.

12

También puede hacerlo de forma multiplataforma con GTK.

Eso no sería muy diferente de hacerlo con 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

Este enfoque se ve muy limpio y directo. Definitivamente lo tendré en cuenta. Aunque sería muy similar, me gustaría ver algunos ejemplos en Haskell, ya que todavía soy un principiante. –

+0

@ M. Ferguson, aquí tienes.Resultó ser ligeramente diferente: no encontré el equivalente a 'gdk_get_default_root_window', por lo que se necesitaba una llamada adicional a' screenGetDefault'. – Rotsor

+0

@Rotsor 'gdk_get_default_root_window' se envuelve con' Graphics.UI.Gtk.Gdk.DrawWindow.drawWindowGetDefaultRootWindow', no es lo más fácil de encontrar aunque –