Chcę zrobić zrzut ekranu za pomocą skryptu w Pythonie i dyskretnie go zapisać.
Interesuje mnie tylko rozwiązanie Linux i powinienem obsługiwać każde środowisko oparte na X.
Chcę zrobić zrzut ekranu za pomocą skryptu w Pythonie i dyskretnie go zapisać.
Interesuje mnie tylko rozwiązanie Linux i powinienem obsługiwać każde środowisko oparte na X.
Odpowiedzi:
Działa to bez konieczności używania moszny lub ImageMagicka.
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."
Pożyczone z http://ubuntuforums.org/showpost.php?p=2681009&postcount=5
Zbierz wszystkie odpowiedzi w jednej klasie. Wyświetla obraz 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()
getScreenByWx
metoda zawodzi wx._core.PyNoAppError: The wx.App object must be created first!
. Co zabawne, kod działa dobrze, jeśli wpisujesz go wiersz po wierszu w powłoce Pythona, ale w skrypcie nie działa.
getScreenByWx
powinieneś a) wymienićmyBitmap
na bmp
i b) zapisać wx.App()
w zmiennej. W getScreenByGtk
zamian (pb != None)
za pb is None
. I nie używaj Qt, więc - nie możesz utworzyć dwa razy QApplication
- Twoja aplikacja ulegnie awarii przy próbie utworzenia jej po raz drugi.
Tylko dla kompletności: Xlib - ale jest nieco powolny podczas przechwytywania całego ekranu:
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()
Można spróbować wrzucić niektóre typy do plików wąskich gardeł w PyXlib, a następnie skompilować je za pomocą Cythona. Może to nieco zwiększyć prędkość.
Edycja: Możemy napisać rdzeń funkcji w C, a następnie użyć go w Pythonie z ctypes, oto coś, co zhakowałem razem:
#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);
}
A potem plik pythona:
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()
#include <X11/Xutil.h>
zamiast tego musiałem #include <X11/Xlib.h>
. Również do opracowania, musiałem przenieść -lX11
się do końca jak to: gcc -shared -O3 -Wall -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c -lX11
.
Ten działa na X11, a może też na Windowsie (ktoś, proszę, sprawdź). Potrzebuje PyQt4 :
import sys
from PyQt4.QtGui import QPixmap, QApplication
app = QApplication(sys.argv)
QPixmap.grabWindow(QApplication.desktop().winId()).save('test.png', 'png')
Mam projekt opakowania ( pyscreenshot ) dla scrot, imagemagick, pyqt, wx i pygtk. Jeśli masz jeden z nich, możesz go użyć. Wszystkie rozwiązania są zawarte w tej dyskusji.
Zainstalować:
easy_install pyscreenshot
Przykład:
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')
pyscreenshot.tempexport.RunProgError: No protocol specified giblib error: Can't open X display. It *is* running, yeah?" timeout_happened=False>
Rozwiązanie wieloplatformowe wykorzystujące 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)
import ImageGrab
img = ImageGrab.grab()
img.save('test.jpg','JPEG')
wymaga to biblioteki obrazów Python
Możesz tego użyć
import os
os.system("import -window root screen_shot.png")
Nie mogłem zrobić zrzutu ekranu w Linuksie z pyscreenshot lub scrot, ponieważ wynik pyscreenshot
był tylko plikiem obrazu png czarnego ekranu.
ale dzięki Bogu istniał inny bardzo łatwy sposób na zrobienie zrzutu ekranu w Linuksie bez instalowania czegokolwiek. po prostu umieść poniższy kod w swoim katalogu i uruchom zpython demo.py
import os
os.system("gnome-screenshot --file=this_directory.png")
istnieje również wiele dostępnych opcji 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
Z tego wątku :
import os
os.system("import -window root temp.png")
dla ubuntu to działa dla mnie, możesz zrobić zrzut ekranu okna wyboru za pomocą tego:
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())
aby przekształcić pixbuf w tablicę
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)
To stare pytanie. Chciałbym odpowiedzieć za pomocą nowych narzędzi.
Działa z Pythonem 3 (powinien działać z Pythonem 2, ale nie testowałem tego) i PyQt5.
Minimalny przykład pracy. Skopiuj go do powłoki Pythona i uzyskaj wynik.
from PyQt5.QtWidgets import QApplication
app = QApplication([])
screen = app.primaryScreen()
screenshot = screen.grabWindow(QApplication.desktop().winId())
screenshot.save('/tmp/screenshot.png')
Spróbuj:
#!/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."
while
pętla, która nigdy nie wychodzi (i używa 1
zamiast niej True
), if (pb != None):
zamiast po prostu if pb:
ma kilka bezcelowych nieprzetworzonych ciągów.