Linux'ta bir Python betiği ile ekran görüntüsü alın


83

Bir python betiği aracılığıyla ekran görüntüsü almak ve göze çarpmadan kaydetmek istiyorum.

Ben sadece Linux çözümüyle ilgileniyorum ve herhangi bir X tabanlı ortamı desteklemeliyim.


Scrot kullanamamanın bir nedeni var mı?
Mark

Aşağıda önerilen yöntemlerin performansını kontrol etmeyi merak ediyorum.
JDong

4
Mark

@Mark -: - / Ne yazık ki, Scrot OS X ile gelmiyor (biliyorum, bu bir Linux sorusuydu. Normalde Linux için geçerli olan her şey OS X için de geçerli olabilir.)
ArtOfWarfare

Ahh evet, OS X'te ekran görüntüsü.
Mark

Yanıtlar:


65

Bu, scrot veya ImageMagick kullanmak zorunda kalmadan çalışır.

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."

Http://ubuntuforums.org/showpost.php?p=2681009&postcount=5 adresinden ödünç alınmıştır.


Bu, glade kullanan GUI tabanlı uygulamada çalışmaz ve hızlı bir şekilde bu kodu geliştirebilir misiniz?
Subodh Ghulaxe

Bu kodu çalıştırdığımda (sanal kutuda linux mint 16 kullanarak) ortaya çıkan görüntü tamamen siyah oluyor. neden olduğu hakkında bir fikrin var mı?
bab

Bazen renklerin kodlaması kapalıdır. Oldukça can sıkıcı. Github.com/JDong820/neobot/blob/master/Linux/Robot/screen.py'nin size herhangi bir yardımı olup olmadığına bakın ; get_rowstride çağrısına dikkat edin.
JDong

48

Tüm cevapları tek bir sınıfta toplayın. PIL görüntüsünü çıkarır.

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

Bu gönderiden bu yana wxWidgets'de bir değişiklik olup olmadığını bilmiyorum, ancak getScreenByWxyöntem başarısız oluyor wx._core.PyNoAppError: The wx.App object must be created first!. Yeterince komik bir şekilde, python kabuğuna satır satır giriyorsanız, ancak bir komut dosyasında başarısız olur.
CadentOrange

Kodunuzu test etmelisiniz! Ya da değil senin, sen de ... bunu yayınlama eğer getScreenByWxbir) değiştirmelidir sizin myBitmaptarafından bmptasarruf) ve b wx.App()bir değişken içine. In getScreenByGtkyerini (pb != None)etmek pb is None. Ve Qt'yi bu nedenle kullanmayın - iki kez oluşturamazsınız QApplication- uygulamanız ikinci kez oluşturmaya çalışırken çökecektir.
Jüri

44

Tamlık için: Xlib - Ancak tüm ekranı yakalarken biraz yavaş:

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

PyXlib'deki darboğaz dosyalarındaki bazı türleri taramaya ve sonra Cython kullanarak derlemeye çalışabiliriz. Bu, hızı biraz artırabilir.


Düzenleme: Fonksiyonun çekirdeğini C'ye yazabiliriz ve sonra ctypes'ten python'da kullanabiliriz, işte birlikte hacklediğim bir şey:

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

Ve sonra python dosyası:

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

4
En azından diğer cevaplardan daha fazla oy kullanmasa da, bu altın değerinde. Sağlam bir çalışma ve bir de yerli! Şerefe!
Torxed

2
hızlı bir yol arayanlar için: Bu yaklaşım 1000 x 1000 boyutundaki bir resim için ortalama ~ 25 ms sürer.
DiCaprio

1
@JHolta, çekilen görüntünün kalitesini değiştirmenin bir yolunu biliyor musunuz? (daha da hızlanmak için)
DiCaprio

6
Bu harika çalışıyor ama #include <X11/Xutil.h>bunun yerine yapmak zorundaydım #include <X11/Xlib.h>. Ayrıca derleme, ben taşınmak zorunda -lX11böyle sona: gcc -shared -O3 -Wall -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c -lX11.
Josh

2
Daha fazla stres testinin ardından bu, arka arkaya birçok kare yakalarken kaynakları çeşitli şekillerde sızdırır. Varsayılan olarak 255 istemciyle sınırlı olduğuna inandığım X11 ekranını yayınlamalısınız. Bu sınırı artırsanız bile, görüntüyü / pencereyi de serbest bırakmayarak, sonunda belleğiniz tükenir. Yukarıda bu sorunları ele alan bir düzenleme gönderdim.
Josh

18

Bu, X11'de ve belki Windows'ta da çalışır (birisi, lütfen kontrol edin). İhtiyaç PyQt4 :

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

2
Lütfen PyQt'un Python ve Qt'den daha kısıtlayıcı olan lisanslamasına dikkat edin. riverbankcomputing.co.uk/software/pyqt/license
user120242

"Kutudan çıkar çıkmaz" Linux kurulumlarımda çalışan tek çözüm budur. Nedenini bilmiyorum ama PyWX, PyGtk, ImageGrab yokken her yerde PyQt4 var. - Teşekkürler :).
Grzegorz Wierzowiecki

Kod az önce çalıştı (Windows 7 x64 - Python 2.7.5; Pythonxy dağıtımı). Jpeg de mevcut (örneğin ... .save ('d: /test.jpg', 'jpeg'))
Mohamad Fakih

16

Scrot, imagemagick, pyqt, wx ve pygtk için bir sarmalayıcı projem ( pyscreenshot ) var. Onlardan birine sahipseniz, onu kullanabilirsiniz. Tüm çözümler bu tartışmaya dahildir.

Yüklemek:

easy_install pyscreenshot

Misal:

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

ImportError: gtkpixbuf adı içe aktarılamıyor
tommy.carstensen

bana şu hatayı veriyor:pyscreenshot.tempexport.RunProgError: No protocol specified giblib error: Can't open X display. It *is* running, yeah?" timeout_happened=False>
Jasar Orion

9

WxPython kullanarak çapraz platform çözümü :

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)

Python kodu içinde yorumlar, açıklamalar ve bağlam içeren referanslar. blog.pythonlibrary.org/2010/04/16/… veya blog.pythonlibrary.org/2010/04/16/…
Civilian


5

Bunu kullanabilirsin

import os
os.system("import -window root screen_shot.png")

Görüntüyü bir arka plan programından aldığınızda bu iyi bir yaklaşımdır, ancak program odaklanmışsa bir istisna döndüreceğini bilmek iyidir.
Lucas Araújo

3

biraz geç ama boşver kolay biri

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

3

Linux'ta ekran görüntüsü veya scrot ile ekran görüntüsü alamadım çünkü çıktısı pyscreenshotsadece siyah ekran png görüntü dosyasıydı.

ama Tanrıya şükür, Linux'ta hiçbir şey yüklemeden ekran görüntüsü almanın çok kolay bir yolu daha vardı. sadece aşağıdaki kodu dizininize koyun vepython demo.py

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

ayrıca birçok seçenek vardır: 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

2

Bu Autopy için bir python paketi var

Bitmap modülü ekran yakalayabilir (bitmap.capture_screen) Çok katmanlı biçimlidir (Windows, Linux, Osx).



1

ubuntu için bu benim için çalışıyor, bununla seçilen pencerenin ekran görüntüsünü alabilirsin:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk
from gi.repository import GdkPixbuf
import numpy as np
from Xlib.display import Display

#define the window name
window_name = 'Spotify'

#define xid of your select 'window'
def locate_window(stack,window):
    disp = Display()
    NET_WM_NAME = disp.intern_atom('_NET_WM_NAME')
    WM_NAME = disp.intern_atom('WM_NAME') 
    name= []
    for i, w in enumerate(stack):
        win_id =w.get_xid()
        window_obj = disp.create_resource_object('window', win_id)
        for atom in (NET_WM_NAME, WM_NAME):
            window_name=window_obj.get_full_property(atom, 0)
            name.append(window_name.value)
    for l in range(len(stack)):
        if(name[2*l]==window):
            return stack[l]

window = Gdk.get_default_root_window()
screen = window.get_screen()
stack = screen.get_window_stack()
myselectwindow = locate_window(stack,window_name)
img_pixbuf = Gdk.pixbuf_get_from_window(myselectwindow,*myselectwindow.get_geometry()) 

pixbuf'u diziye dönüştürmek için

def pixbuf_to_array(p):
    w,h,c,r=(p.get_width(), p.get_height(), p.get_n_channels(), p.get_rowstride())
    assert p.get_colorspace() == GdkPixbuf.Colorspace.RGB
    assert p.get_bits_per_sample() == 8
    if  p.get_has_alpha():
        assert c == 4
    else:
        assert c == 3
    assert r >= w * c
    a=np.frombuffer(p.get_pixels(),dtype=np.uint8)
    if a.shape[0] == w*c*h:
        return a.reshape( (h, w, c) )
    else:
        b=np.zeros((h,w*c),'uint8')
        for j in range(h):
            b[j,:]=a[r*j:r*j+w*c]
        return b.reshape( (h, w, c) )

beauty_print = pixbuf_to_array(img_pixbuf)

0

Bu eski bir soru. Yeni araçlar kullanarak cevaplamak istiyorum.

Python 3 (python 2 ile çalışmalı, ancak test etmedim) ve PyQt5 ile çalışır.

Minimal çalışma örneği. Python kabuğuna kopyalayın ve sonucu alın.

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

bu işlevin tamamlanması için ortalama süreniz var mı? Sadece faiz değerinde o takdirde
DiCaprio

1
@Mrlenny 300 ms (tam kod için), 165 ms (kodun son üç satırı).
rominf

-3

Dene:

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

4
Bu saçmalık nedir? İçe aktarımların yarısı işe yaramaz, whilehiçbir zaman çıkmayan (ve 1yerine kullanan True) bir döngü var if (pb != None):, sadece yerine if pb:bazı anlamsız ham dizelere sahip.
ArtOfWarfare
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.