2008-09-16 14 views
69

Quiero tomar una captura de pantalla a través de un script python y guardarlo discretamente.Tome una captura de pantalla a través de una secuencia de comandos python. [Linux]

Solo estoy interesado en la solución Linux y debería soportar cualquier entorno basado en X.

+0

algún motivo no se puede utilizar [scrot] (http: //linux.die .net/man/1/scrot)? – Mark

+0

Tengo curiosidad por comprobar el rendimiento de los métodos sugeridos a continuación. – JDong

+0

@Mark - Enlace muerto. – ArtOfWarfare

Respuesta

59

Esto funciona sin tener que utilizar scrot o ImageMagick.

import gtk.gdk 

w = gtk.gdk.get_default_root_window() 
sz = w.get_size() 
print "The size of the window is %d x %d" % sz 
pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1]) 
pb = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1]) 
if (pb != None): 
    pb.save("screenshot.png","png") 
    print "Screenshot saved to screenshot.png." 
else: 
    print "Unable to get the screenshot." 

tomado de http://ubuntuforums.org/showpost.php?p=2681009&postcount=5

+0

Esto no funciona en la aplicación basada en GUI que usa glade y rápidamente, puede mejorar este código. –

+0

Cuando ejecuto este código (usando linux mint 16 en virtualbox) la imagen resultante es completamente negra. ¿Tienes alguna idea de por qué? – bab

+0

Algunas veces la codificación de los colores está desactivada. Es bastante molesto Vea si https://github.com/JDong820/neobot/blob/master/Linux/Robot/screen.py es de alguna ayuda para usted; fíjate en la llamada a get_rowstride. – JDong

3

Parece que una búsqueda corta gtkShots podría ayudarlo, ya que es un programa de captura de pantalla python GPL, por lo que debe tener lo que necesita en él.

7
import ImageGrab 
img = ImageGrab.grab() 
img.save('test.jpg','JPEG') 

esto requiere Python Imaging Library

+18

sólo funciona con Windows: http://www.pythonware.com/library/ pil/handbook/imagegrab.htm – bernie

18

Esta funciona en X11, y quizás también en Windows (a alguien, por favor marque). Necesidades PyQt4:

import sys 
from PyQt4.QtGui import QPixmap, QApplication 
app = QApplication(sys.argv) 
QPixmap.grabWindow(QApplication.desktop().winId()).save('test.png', 'png') 
+2

Tome nota de la licencia de PyQt, que es más restrictiva que Python y Qt. http://www.riverbankcomputing.co.uk/software/pyqt/license – user120242

+0

usuario kmilin (abajo) informa de que esto no funciona en Windows –

+0

Es la única solución que se ejecuta en mis instalaciones de Linux "out-of-the-box" . No sé por qué, pero tengo PyQt4 en todas partes, aunque carezco de PyWX, PyGtk, ImageGrab. - Gracias :). –

8

solución de plataforma cruzada usando wxPython:

import wx 
wx.App() # Need to create an App instance before doing anything 
screen = wx.ScreenDC() 
size = screen.GetSize() 
bmp = wx.EmptyBitmap(size[0], size[1]) 
mem = wx.MemoryDC(bmp) 
mem.Blit(0, 0, size[0], size[1], screen, 0, 0) 
del mem # Release bitmap 
bmp.SaveFile('screenshot.png', wx.BITMAP_TYPE_PNG) 
+0

Referencias, con comentarios, explicación y contexto dentro del código python. http://www.blog.pythonlibrary.org/2010/04/16/how-to-take-a-screenshot-of-your-wxpython-app-and-print-it/ o http://www.blog .pythonlibrary.org/2010/04/16/how-to-take-a-screenshot-of-your-wxpython-app-and-print-it/ – Civilian

41

Compilar todas las respuestas en una clase. Muestra la imagen PIL.

#!/usr/bin/env python 
# encoding: utf-8 
""" 
screengrab.py 

Created by Alex Snet on 2011-10-10. 
Copyright (c) 2011 CodeTeam. All rights reserved. 
""" 

import sys 
import os 

import Image 


class screengrab: 
    def __init__(self): 
     try: 
      import gtk 
     except ImportError: 
      pass 
     else: 
      self.screen = self.getScreenByGtk 

     try: 
      import PyQt4 
     except ImportError: 
      pass 
     else: 
      self.screen = self.getScreenByQt 

     try: 
      import wx 
     except ImportError: 
      pass 
     else: 
      self.screen = self.getScreenByWx 

     try: 
      import ImageGrab 
     except ImportError: 
      pass 
     else: 
      self.screen = self.getScreenByPIL 


    def getScreenByGtk(self): 
     import gtk.gdk  
     w = gtk.gdk.get_default_root_window() 
     sz = w.get_size() 
     pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1]) 
     pb = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1]) 
     if pb is None: 
      return False 
     else: 
      width,height = pb.get_width(),pb.get_height() 
      return Image.fromstring("RGB",(width,height),pb.get_pixels()) 

    def getScreenByQt(self): 
     from PyQt4.QtGui import QPixmap, QApplication 
     from PyQt4.Qt import QBuffer, QIODevice 
     import StringIO 
     app = QApplication(sys.argv) 
     buffer = QBuffer() 
     buffer.open(QIODevice.ReadWrite) 
     QPixmap.grabWindow(QApplication.desktop().winId()).save(buffer, 'png') 
     strio = StringIO.StringIO() 
     strio.write(buffer.data()) 
     buffer.close() 
     del app 
     strio.seek(0) 
     return Image.open(strio) 

    def getScreenByPIL(self): 
     import ImageGrab 
     img = ImageGrab.grab() 
     return img 

    def getScreenByWx(self): 
     import wx 
     wx.App() # Need to create an App instance before doing anything 
     screen = wx.ScreenDC() 
     size = screen.GetSize() 
     bmp = wx.EmptyBitmap(size[0], size[1]) 
     mem = wx.MemoryDC(bmp) 
     mem.Blit(0, 0, size[0], size[1], screen, 0, 0) 
     del mem # Release bitmap 
     #bmp.SaveFile('screenshot.png', wx.BITMAP_TYPE_PNG) 
     myWxImage = wx.ImageFromBitmap(myBitmap) 
     PilImage = Image.new('RGB', (myWxImage.GetWidth(), myWxImage.GetHeight())) 
     PilImage.fromstring(myWxImage.GetData()) 
     return PilImage 

if __name__ == '__main__': 
    s = screengrab() 
    screen = s.screen() 
    screen.show() 
+0

No sé si ha habido un cambio en wxWidgets desde esta publicación, pero el método 'getScreenByWx' falla con' wx._core.PyNoAppError: ¡El objeto wx.App debe crearse primero! '. Curiosamente, el código funciona bien si lo estás ingresando línea por línea en el shell de Python, pero falla en un script. – CadentOrange

+0

¡Debes probar tu código! O no, si lo está publicando ... En 'getScreenByWx' debería a) reemplazar' myBitmap' por 'bmp' y b) guardar' wx.App() 'en una variable. En 'getScreenByGtk', reemplace' (pb! = None) 'por' pb is None'. Y no use Qt, así que no puede crear dos veces 'QApplication'; su aplicación se bloqueará al intentar crearla por segunda vez. – Jury

12

Tengo un proyecto envoltorio (pyscreenshot) para scrot, ImageMagick, pyqt, wx y pygtk. Si tiene uno de ellos, puede usarlo. Todas las soluciones están incluidas en esta discusión.

Instalar:

easy_install pyscreenshot 

Ejemplo:

import pyscreenshot as ImageGrab 

# fullscreen 
im=ImageGrab.grab() 
im.show() 

# part of the screen 
im=ImageGrab.grab(bbox=(10,10,500,500)) 
im.show() 

# to file 
ImageGrab.grab_to_file('im.png') 
+0

ImportError: no se puede importar el nombre gtkpixbuf –

29

simplemente para la corrección: Xlib - Pero es algo lento al capturar toda la pantalla:

from Xlib import display, X 
import Image #PIL 

W,H = 200,200 
dsp = display.Display() 
root = dsp.screen().root 
raw = root.get_image(0, 0, W,H, X.ZPixmap, 0xffffffff) 
image = Image.fromstring("RGB", (W, H), raw.data, "raw", "BGRX") 
image.show() 

Se podría tratar de trow algunos tipos en los archivos de cuello de botella en PyXlib, y luego compilarlo usando Cython . Eso podría aumentar la velocidad un poco.


Editar: Podemos escribir el núcleo de la función en C y, a continuación, utilizarlo en pitón de ctypes, aquí es algo que hackeado:

#include <stdio.h> 
#include <X11/X.h> 
#include <X11/Xlib.h> 
//Compile hint: gcc -shared -O3 -lX11 -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c 

void getScreen(const int, const int, const int, const int, unsigned char *); 
void getScreen(const int xx,const int yy,const int W, const int H, /*out*/ unsigned char * data) 
{ 
    Display *display = XOpenDisplay(NULL); 
    Window root = DefaultRootWindow(display); 

    XImage *image = XGetImage(display,root, xx,yy, W,H, AllPlanes, ZPixmap); 

    unsigned long red_mask = image->red_mask; 
    unsigned long green_mask = image->green_mask; 
    unsigned long blue_mask = image->blue_mask; 
    int x, y; 
    int ii = 0; 
    for (y = 0; y < H; y++) { 
     for (x = 0; x < W; x++) { 
     unsigned long pixel = XGetPixel(image,x,y); 
     unsigned char blue = (pixel & blue_mask); 
     unsigned char green = (pixel & green_mask) >> 8; 
     unsigned char red = (pixel & red_mask) >> 16; 

     data[ii + 2] = blue; 
     data[ii + 1] = green; 
     data[ii + 0] = red; 
     ii += 3; 
     } 
    } 
    XDestroyImage(image); 
    XDestroyWindow(display, root); 
    XCloseDisplay(display); 
} 

Y entonces el pitón -file:

import ctypes 
import os 
from PIL import Image 

LibName = 'prtscn.so' 
AbsLibPath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + LibName 
grab = ctypes.CDLL(AbsLibPath) 

def grab_screen(x1,y1,x2,y2): 
    w, h = x2-x1, y2-y1 
    size = w * h 
    objlength = size * 3 

    grab.getScreen.argtypes = [] 
    result = (ctypes.c_ubyte*objlength)() 

    grab.getScreen(x1,y1, w, h, result) 
    return Image.frombuffer('RGB', (w, h), result, 'raw', 'RGB', 0, 1) 

if __name__ == '__main__': 
    im = grab_screen(0,0,1440,900) 
    im.show() 
+2

Esto vale oro, si no al menos más votos que las otras respuestas. ¡Un trabajo sólido y uno nativo también! ¡Aclamaciones! – Torxed

+1

para aquellos que buscan una forma rápida: este enfoque toma ~ 25ms en promedio para una foto de tamaño 1000 x 1000. – Mrlenny

+1

@JHolta, ¿conoce una forma de cambiar la calidad de la imagen capturada? (para acelerar aún más) – Mrlenny

-3

Inténtelo:

#!/usr/bin/python 

import gtk.gdk 
import time 
import random 
import socket 
import fcntl 
import struct 
import getpass 
import os 
import paramiko  

while 1: 
    # generate a random time between 120 and 300 sec 
    random_time = random.randrange(20,25) 
    # wait between 120 and 300 seconds (or between 2 and 5 minutes) 

    print "Next picture in: %.2f minutes" % (float(random_time)/60) 

    time.sleep(random_time) 
    w = gtk.gdk.get_default_root_window() 
    sz = w.get_size() 
    print "The size of the window is %d x %d" % sz 
    pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1]) 
    pb = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1]) 
    ts = time.asctime(time.localtime(time.time())) 
    date = time.strftime("%d-%m-%Y") 
    timer = time.strftime("%I:%M:%S%p") 
    filename = timer 
    filename += ".png" 

    if (pb != None): 
     username = getpass.getuser() #Get username 
     newpath = r'screenshots/'+username+'/'+date #screenshot save path 
     if not os.path.exists(newpath): os.makedirs(newpath) 
     saveas = os.path.join(newpath,filename) 
     print saveas 
     pb.save(saveas,"png") 
    else: 
     print "Unable to get the screenshot." 
+1

¿Qué es esta basura? La mitad de las importaciones son inútiles, hay un bucle 'while' que nunca sale (y usa '1' en lugar de' True'), tiene 'if (pb! = None):' en lugar de solo 'if pb:', tiene alguna Cuerdas sin sentido sin sentido. – ArtOfWarfare

2

Hay un paquete python para este módulo Autopy

El mapa de bits se pueden agarrar a la pantalla (bitmap.capture_screen) Es multiplateform (Windows, Linux, OSX).

0

Es una vieja pregunta. Me gustaría responderlo usando nuevas herramientas.

Obras con Python 3 (debería funcionar con Python 2, pero no he probarlo) y PyQt5.

Ejemplo de trabajo mínimo. Cópialo en el shell python y obtén el resultado.

from PyQt5.QtWidgets import QApplication 
app = QApplication([]) 
screen = app.primaryScreen() 
screenshot = screen.grabWindow(QApplication.desktop().winId()) 
screenshot.save('/tmp/screenshot.png') 
+0

¿tiene el tiempo promedio para completar esta función? solo interés si vale la pena – Mrlenny

+1

@Mrlenny 300 ms (para código completo), 165 ms (últimas tres líneas de código). – rominf

2

poco tarde, pero no importa es fácil

import autopy 
import time 
time.sleep(2) 
b = autopy.bitmap.capture_screen() 
b.save("C:/Users/mak/Desktop/m.png") 
1

que no podía tomar captura de pantalla en Linux con pyscreenshot o scrot porque la producción de pyscreenshot era sólo una archivo de imagen png de pantalla negra.

pero gracias a Dios no había otra forma muy fácil para tomar captura de pantalla en Linux sin instalar nada. sólo hay que poner debajo de código en su directorio y correr con python demo.py

import os 
os.system("gnome-screenshot --file=this_directory.png") 

También hay muchas opciones disponibles para gnome-screenshot --help

Application Options: 
    -c, --clipboard    Send the grab directly to the clipboard 
    -w, --window     Grab a window instead of the entire screen 
    -a, --area      Grab an area of the screen instead of the entire screen 
    -b, --include-border   Include the window border with the screenshot 
    -B, --remove-border   Remove the window border from the screenshot 
    -p, --include-pointer   Include the pointer with the screenshot 
    -d, --delay=seconds   Take screenshot after specified delay [in seconds] 
    -e, --border-effect=effect  Effect to add to the border (shadow, border, vintage or none) 
    -i, --interactive    Interactively set options 
    -f, --file=filename   Save screenshot directly to this file 
    --version      Print version information and exit 
    --display=DISPLAY    X display to use 
Cuestiones relacionadas