2008-09-16 7 views
69

Je veux faire une capture d'écran via un script python et le sauvegarder discrètement.Faites une capture d'écran via un script python. [Linux]

Je ne suis intéressé que par la solution Linux, et je devrais prendre en charge tout environnement basé sur X.

+0

une raison quelconque vous ne pouvez pas utiliser [scrot] (http: //linux.die .net/man/1/scrot)? – Mark

+0

Je suis curieux de vérifier les performances des méthodes suggérées ci-dessous. – JDong

+0

@Mark - Lien mort. – ArtOfWarfare

Répondre

59

Cela fonctionne sans avoir à utiliser scrot ou 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." 

Emprunté à http://ubuntuforums.org/showpost.php?p=2681009&postcount=5

+0

Cela ne fonctionne pas dans une application basée sur l'interface graphique utilisant glade et rapidement, pouvez-vous améliorer ce code. –

+0

Lorsque j'exécute ce code (en utilisant linux mint 16 dans virtualbox) l'image résultante est complètement noire. Avez-vous une idée pourquoi? – bab

+0

Parfois, l'encodage des couleurs est désactivé. C'est assez énervant. Voyez si https://github.com/JDong820/neobot/blob/master/Linux/Robot/screen.py peut vous aider; Notez l'appel à get_rowstride. – JDong

3

Une petite recherche apparue gtkShots a l'air de vous aider, car il s'agit d'un programme de capture d'écran GPLed python, alors vous devriez avoir ce dont vous avez besoin.

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

cela nécessite Python Imaging Library

+18

Fonctionne uniquement sur Windows: http://www.pythonware.com/library/ pil/handbook/imagegrab.htm – bernie

18

Celui-ci fonctionne sur X11, et peut-être également sous Windows (quelqu'un, vérifiez s'il vous plaît). A besoin PyQt4:

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

Veuillez prendre note des licences de PyQt, qui sont plus restrictives que Python et Qt. http://www.riverbankcomputing.co.uk/software/pyqt/license – user120242

+0

utilisateur kmilin (ci-dessous) signale que cela fonctionne sur Windows –

+0

C'est la seule solution qui fonctionne sur mes installations Linux "out-of-the-box" . Je ne sais pas pourquoi, mais j'ai PyQt4 partout, alors que le manque de PyWX, PyGtk, ImageGrab. - Merci :). –

8

solution de plate-forme à l'aide de la Croix-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

Références, avec commentaires, explications et contexte dans le code python. http://www.blog.pythonlibrary.org/2010/04/16/how-to-take-a-screenshot-of-your-wxpython-app-and-print-it/ ou http://www.blog .pythonlibrary.org/2010/04/16/comment-prendre-une-capture d'écran-de-votre-wxpython-app-and-print-it/ – Civilian

41

Compile toutes les réponses dans une classe. Sorties Image 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

Je ne sais pas s'il y a eu un changement de wxWidgets depuis ce post, mais la méthode 'getScreenByWx' échoue avec' wx._core.PyNoAppError: l'objet wx.App doit être créé en premier! '. Curieusement, le code fonctionne bien si vous l'entrez ligne par ligne dans le shell python mais dans un script il échoue. – CadentOrange

+0

Vous devriez tester votre code! Ou, pas votre, si vous le publiez ... Dans 'getScreenByWx' vous devriez a) remplacer' myBitmap' par 'bmp' et b) sauver' wx.App() 'dans une variable. Dans 'getScreenByGtk', remplacez' (pb! = None) 'par' pb is None'. Et n'utilisez pas Qt donc - vous ne pouvez pas créer deux fois 'QApplication' - votre application va planter pour essayer de la créer une seconde fois. – Jury

12

J'ai un projet d'emballage (pyscreenshot) pour scrot, ImageMagick, PyQt, WX et pygtk. Si vous en avez un, vous pouvez l'utiliser. Toutes les solutions sont incluses dans cette discussion.

Installer:

easy_install pyscreenshot 

Exemple:

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: impossible d'importer le nom gtkpixbuf –

29

Juste pour être complet: Xlib - Mais il est un peu lent lors de la capture de l'écran entier:

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() 

On pourrait essayer de trow quelques types dans les fichiers bottleneck dans PyXlib, puis compilez-le en utilisant Cython . Cela pourrait augmenter la vitesse un peu.


Edit: Nous pouvons écrire le noyau de la fonction C, puis l'utiliser en python de ctypes, voici quelque chose que je piraté ensemble:

#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); 
} 

Et puis le python -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

Cela vaut de l'or, sinon au moins plus de votes que les autres réponses. Un travail solide et un natif aussi! À votre santé! – Torxed

+1

pour ceux qui cherchent un moyen rapide: cette approche prend ~ 25ms en moyenne pour une photo de taille 1000 x 1000. – Mrlenny

+1

@JHolta, savez-vous un moyen de changer la qualité de l'image capturée? (afin d'accélérer encore plus) – Mrlenny

-3

Essayez:

#!/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

Quelle est cette merde? La moitié des imports est inutile, il y a une boucle 'while' qui ne sort jamais (et utilise' 1' au lieu de 'True'), a' if (pb! = None): 'au lieu de simplement' si pb: ', a chaînes brutes inutiles. – ArtOfWarfare

2

Il y a un paquet python pour cette Autopy

Le module bitmap peut saisir à l'écran (bitmap.capture_screen) Il est multiplateforme (Windows, Linux, Mac OSX).

0

C'est une vieille question. Je voudrais y répondre en utilisant de nouveaux outils.

Fonctionne avec python 3 (devrait fonctionner avec python 2, mais je ne l'ai pas testé) et PyQt5.

Exemple de travail minimal. Copiez-le dans le shell python et obtenez le résultat.

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

avez-vous le temps moyen pour cette fonction à remplir? juste intérêt si en vaut la peine – Mrlenny

+1

@Mrlenny 300 ms (pour le code complet), 165 ms (trois dernières lignes de code). – rominf

2

peu tard, mais tant pis facile est un

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

Je ne pouvais pas prendre capture d'écran sous Linux avec pyscreenshot ou scrot parce que la production de pyscreenshot était juste un fichier d'image png écran noir.

Mais, Dieu merci, il y avait un autre moyen très facile de prendre des captures d'écran sous Linux sans rien installer. il suffit de mettre le code ci-dessous dans votre répertoire et exécuter avec python demo.py

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

aussi il y a beaucoup d'options disponibles pour 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 
Questions connexes