Сделайте снимок экрана с помощью скрипта Python в Linux

Я хочу сделать снимок экрана с помощью скрипта python и ненавязчиво его сохранить.

Меня интересует только решение для Linux, и я должен поддерживать любую среду на основе X.

По какой причине вы не можете использовать мошонка?

Mark 20.04.2009 14:46

Мне любопытно проверить производительность предложенных ниже методов.

JDong 01.07.2014 21:01

Новая ссылка: manpages.ubuntu.com/manpages/karmic/man1/scrot.1.html (@ArtOfWarfare)

Mark 02.08.2015 00:24

@Mark -: - / К сожалению, Scrot не поставляется с OS X (я знаю, это был вопрос Linux. Обычно все, что применимо к Linux, также может применяться к OS X дословно).

ArtOfWarfare 02.08.2015 00:41

Ах да, это снимок экрана на OS X.

Mark 02.08.2015 02:32
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
86
5
103 137
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

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

для этого требуется библиотека изображений Python

Работает только в Windows: pythonware.com/library/pil/handbook/imagegrab.htm

mechanical_meat 04.04.2009 23:52

Этот работает на X11, а возможно, и на Windows (кто-нибудь, пожалуйста, проверьте). Требуется PyQt4:

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

Обратите внимание на лицензирование PyQt, которое является более строгим, чем Python и Qt. riverbankcomputing.co.uk/software/pyqt/license

user120242 13.08.2009 09:09

Это единственное решение, которое работает на моих установках Linux "из коробки". Не знаю почему, но у меня везде PyQt4, а PyWX, PyGtk, ImageGrab не хватает. - Спасибо :).

Grzegorz Wierzowiecki 03.02.2012 23:17

Код просто заработал (в Windows 7 x64 - Python 2.7.5; дистрибутив Pythonxy). Также доступен Jpeg (например, ... .save ('d: /test.jpg', 'jpeg'))

Mohamad Fakih 13.08.2013 09:19
Ответ принят как подходящий

Это работает без использования scrot или 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."

Заимствовано у http://ubuntuforums.org/showpost.php?p=2681009&postcount=5

Это не работает в приложении на основе графического интерфейса пользователя, использующем glade, и можете ли вы быстро улучшить этот код.

Subodh Ghulaxe 30.09.2013 10:28

Когда я выполняю этот код (используя linux mint 16 в виртуальном боксе), результирующее изображение становится полностью черным. Вы знаете почему?

bab 03.05.2014 09:18

Иногда кодировка цветов отключена. Это очень раздражает. Посмотрите, поможет ли вам github.com/JDong820/neobot/blob/master/Linux/Robot/screen.py; обратите внимание на вызов get_rowstride.

JDong 01.07.2014 21:00

Кросс-платформенное решение с использованием 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)

Ссылки с комментариями, пояснениями и контекстом в коде Python. blog.pythonlibrary.org/2010/04/16/… или blog.pythonlibrary.org/2010/04/16/…

Civilian 24.09.2011 03:52

Соберите все ответы в одном классе. Выводит изображение 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()

Я не знаю, были ли изменения в wxWidgets после этой публикации, но метод getScreenByWx не работает с wx._core.PyNoAppError: The wx.App object must be created first!. Как ни странно, код работает нормально, если вы вводите его построчно в оболочке python, но в сценарии он не работает.

CadentOrange 18.07.2014 11:57

Вы должны протестировать свой код! Или не ваш, если вы его публикуете ... В getScreenByWx вам следует: а) заменить myBitmap на bmp и б) сохранить wx.App() в переменной. В getScreenByGtk замените (pb != None) на pb is None. И не используйте Qt, поэтому - вы не можете создать QApplication дважды - ваше приложение выйдет из строя при попытке создать его второй раз.

Jury 14.02.2016 20:16

У меня есть проект оболочки (снимок экрана) для scrot, imagemagick, pyqt, wx и pygtk. Если у вас есть один из них, вы можете его использовать. Все решения включены в это обсуждение.

Установить:

easy_install pyscreenshot

Пример:

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

tommy.carstensen 28.12.2013 15:51

это дает мне эту ошибку: pyscreenshot.tempexport.RunProgError: No protocol specified giblib error: Can't open X display. It *is* running, yeah?" timeout_happened=False>

Jasar Orion 28.04.2020 15:09

Просто для полноты: Xlib - Но при захвате всего экрана он несколько медленный:

from Xlib import display, X
import Image #PIL

W,H = 200,200
dsp = display.Display()
try:
    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()
finally:
    dsp.close()

Можно попробовать добавить некоторые типы в файлы-узкие места в PyXlib, а затем скомпилировать их с помощью Cython. Это может немного увеличить скорость.


Редактировать: Мы можем написать ядро ​​функции на C, а затем использовать его в python из ctypes, вот что я вместе взломал:

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

И затем python-файл:

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

Это стоит золота, если не по крайней мере больше голосов, чем другие ответы. Солидная работа и родная тоже! Ваше здоровье!

Torxed 22.12.2015 22:33

для тех, кто ищет быстрый способ: этот подход в среднем занимает ~ 25 мсек для картинки размером 1000 x 1000.

DiCaprio 22.01.2016 17:29

@JHolta, знаете ли вы, как изменить качество захваченного изображения? (чтобы еще больше ускориться)

DiCaprio 22.01.2016 19:23

Неа. В настоящее время он просто копирует изображение рабочего стола как есть, любое преобразование изображения приведет к накладным расходам. Так что без снижения фактического качества рабочего стола вам не повезло с этой идеей. В любом случае, текущие накладные расходы, предположительно, относятся к стороне Python, где мы предварительно выделяем буфер (возможно, это можно сделать в c), и другой медленной части, где PIL читает в этом буфере, и те, и другие могут быть оптимизированы и может быть размещен на конце C.

JHolta 22.01.2016 22:09

Это отлично работает, но мне пришлось использовать #include <X11/Xutil.h> вместо #include <X11/Xlib.h>. Также для компиляции мне пришлось переместить -lX11 в конец вот так: gcc -shared -O3 -Wall -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c -lX11.

Josh 11.08.2016 06:17

При дальнейшем стресс-тестировании это приводит к утечке ресурсов различными способами при последовательном захвате множества кадров. Вы должны освободить дисплей X11, который, как я считаю, по умолчанию ограничен 255 клиентами. Даже если вы увеличите этот предел, не отпуская изображение / окно, в конечном итоге у вас закончится нехватка памяти. Я отправил правку выше, которая решает эти проблемы.

Josh 11.08.2016 06:59

Это наиболее фундаментальный ответ и наиболее эффективный.

étale-cohomology 05.09.2016 13:59

@Mrlenny Меня также интересуют ускорения. Я думаю, что один из вариантов - снизить битовая глубина всей вашей среды X, чтобы XGetImage (который является основной рабочей лошадкой) фактически возвращал изображение более низкого качества.

étale-cohomology 16.09.2016 21:00

0xffffffff, откуда вы узнали, что это 0xffffffff?

Phani Rithvij 29.05.2020 22:19

Попытайся:

#!/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, который никогда не завершается (и использует 1 вместо True), имеет if (pb != None): вместо if pb:, имеет бессмысленные необработанные строки.

ArtOfWarfare 01.08.2015 02:15

Для этого Autopy есть пакет python

Модуль растрового изображения может захватывать экран (bitmap.capture_screen) Он многоплатформенный (Windows, Linux, Osx).

Это старый вопрос. Я хотел бы ответить на него с помощью новых инструментов.

Работает с python 3 (должен работать с python 2, но я его не тестировал) и PyQt5.

Минимальный рабочий пример. Скопируйте его в оболочку Python и получите результат.

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

у вас есть среднее время выполнения этой функции? просто интерес, если оно того стоит

DiCaprio 15.09.2015 22:40

@Mrlenny 300 мс (для полного кода), 165 мс (последние три строки кода).

rominf 16.09.2015 08:29

От эта ветка:

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

немного поздно, но неважно, что это просто

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

Я не мог сделать снимок экрана в Linux с помощью pyscreenshot или scrot, потому что вывод pyscreenshot был просто файлом изображения png с черным экраном.

но, слава богу, был еще один очень простой способ сделать снимок экрана в Linux, ничего не устанавливая. просто поместите код ниже в свой каталог и запустите с python demo.py

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

также есть много доступных опций для 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

Вы можете использовать это

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

Это хороший подход, если вы можете получить изображение из фоновой программы, но хорошо знать, что если программа сфокусирована, она вернет исключение.

Lucas Araújo 19.10.2019 17:47

для ubuntu это работает для меня, вы можете сделать снимок экрана окна выбора с помощью этого:

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 в массив

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)

Другие вопросы по теме