Linux에서 Python 스크립트를 통해 스크린 샷 찍기


81

파이썬 스크립트를 통해 스크린 샷을 찍고 눈에 띄지 않게 저장하고 싶습니다.

저는 Linux 솔루션에만 관심이 있으며 모든 X 기반 환경을 지원해야합니다.


scrot을 사용할 수없는 이유는 무엇입니까?
Mark

아래 제안 된 방법의 성능을 확인하고 싶습니다.
JDong

4
새로운 링크 : manpages.ubuntu.com/manpages/karmic/man1/scrot.1.html (@ArtOfWarfare)
마크

@ 마크 - : - / 유감스럽게도, Scrot (나는이 리눅스 질문이었다, 알고 그냥 일반적으로 리눅스에 적용 무엇도 그대로 OS X에 적용 할 수 있습니다..) OS X와 함께 제공되지 않습니다
ArtOfWarfare

Ahh 맞습니다. OS X
Mark a

답변:


65

이것은 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를 사용하는 GUI 기반 응용 프로그램에서 작동하지 않으며 빠르게이 코드를 개선 할 수 있습니다.
Subodh Ghulaxe 2013 년

이 코드를 실행하면 (virtualbox에서 Linux mint 16 사용) 결과 이미지가 완전히 검은 색입니다. 왜 그런지 아십니까?
bab

때때로 색상의 인코딩이 꺼져 있습니다. 꽤 성가신 일입니다. github.com/JDong820/neobot/blob/master/Linux/Robot/screen.py 가 도움이 되는지 확인 하십시오 . get_rowstride에 대한 호출을 확인하십시오.
JDong

48

모든 답을 한 클래스에 모으십시오. 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!. 재미있게도 파이썬 셸에 한 줄씩 입력하면 코드가 제대로 작동하지만 스크립트에서는 실패합니다.
CadentOrange

코드를 테스트해야합니다! 아니면 아닌, 당신이 ... 그것을 게시하는 경우 getScreenByWx가) 교체해야 당신 myBitmap에 의해 bmp저장)와 b wx.App()변수로. 에서 getScreenByGtk교체 (pb != None)pb is None. 그리고 Qt를 사용하지 마십시오. 두 번 만들 수는 없습니다. 두 번 QApplication만들려고하면 앱이 충돌합니다.
심사 위원

42

완전성을 위해 : Xlib-하지만 전체 화면을 캡처 할 때 다소 느립니다.

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의 병목 파일에서 일부 유형을 검색 한 다음 Cython을 사용하여 컴파일 할 수 있습니다. 속도를 조금 높일 수 있습니다.


편집 : 우리는 C로 함수의 핵심을 작성한 다음 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);
}

그리고 파이썬 파일 :

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

3
이것은 다른 답변보다 적어도 더 많은 찬성표는 아니지만 금 가치가 있습니다. 견고한 작업과 기본 작업도! 건배!
Torxed

1
빠른 방법을 찾고있는 사람들을 위해 :이 방법은 크기 1000의 그림을 위해 ~ 평균은 25ms 소요 X 1000
디카프리오

1
@JHolta, 캡처 한 이미지의 품질을 변경하는 방법을 알고 있습니까? (더 빠른 속도를 위해)
DiCaprio

1
아니. 현재는 데스크톱 이미지를 그대로 복사하고 있으며 이미지를 변환하면 오버 헤드가 발생합니다. 따라서 데스크톱의 실제 품질을 저하시키지 않으면 그 아이디어에 운이 없습니다. 어쨌든, 현재의 오버 헤드는 아마도 파이썬 끝에서 우리가 버퍼를 미리 할당하고 (아마도 c에서 수행 될 수 있음) PIL이이 버퍼에서 읽는 다른 느린 부분에있을 것입니다. 둘 다 최적화 될 수 있습니다. C 끝에 놓을 수 있습니다.
JHolta

6
이것은 훌륭하게 작동하지만 #include <X11/Xutil.h>대신 #include <X11/Xlib.h>. 또한 컴파일 -lX11을 위해 다음과 같이 끝 으로 이동 해야했습니다 gcc -shared -O3 -Wall -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c -lX11.
Josh

18

이것은 X11에서 작동하며 아마도 Windows에서도 작동합니다 (누군가 확인하십시오). PyQt4 필요 :

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

2
Python 및 Qt보다 더 제한적인 PyQt의 라이선스에 유의하십시오. riverbankcomputing.co.uk/software/pyqt/license
user120242

내 Linux 설치에서 "즉시"실행되는 유일한 솔루션입니다. 이유는 모르겠지만 PyWX, PyGtk, ImageGrab이 부족한 반면 PyQt4는 어디에나 있습니다. - 감사 :).
Grzegorz Wierzowiecki

코드는 방금 작동했습니다 (Windows 7 x64-Python 2.7.5; Pythonxy 배포판). Jpeg도 사용 가능합니다 (예 : .save ( 'd : /test.jpg', 'jpeg'))
Mohamad Fakih

15

scrot, imagemagick, pyqt, wx 및 pygtk에 대한 래퍼 프로젝트 ( pyscreenshot )가 있습니다. 그중 하나가 있으면 사용할 수 있습니다. 이 토론에는 모든 솔루션이 포함되어 있습니다.

설치:

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

그것은 나에게이 오류를 준다 :pyscreenshot.tempexport.RunProgError: No protocol specified giblib error: Can't open X display. It *is* running, yeah?" timeout_happened=False>
Jasar Orion

9

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)

주석, 설명 및 파이썬 코드 내 컨텍스트가있는 참조. blog.pythonlibrary.org/2010/04/16/... 또는 blog.pythonlibrary.org/2010/04/16/...
민간


5

이것을 사용할 수 있습니다

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

이것은 일단 백그라운드 프로그램에서 이미지를 가져올 수 있으면 좋은 접근 방식이지만 프로그램에 초점이 맞춰지면 예외가 반환된다는 것을 아는 것이 좋습니다.
Lucas Araújo

3

조금 늦었지만 마음에 들지 않는 쉬운 것은

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

3

pyscreenshot 또는 scrot으로 Linux에서 스크린 샷을 찍을 수 없었습니다.의 출력이 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

2

Autopy를 위한 파이썬 패키지가 있습니다.

비트 맵 모듈은 화면을 잡을 수 있습니다 (bitmap.capture_screen) 멀티 플레이트 형식 (Windows, Linux, Osx)입니다.



1

우분투의 경우이 작업은 다음과 같이 선택 창의 스크린 샷을 찍을 수 있습니다.

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)

0

오래된 질문입니다. 새로운 도구를 사용하여 대답하고 싶습니다.

python 3 (python 2에서 작동해야하지만 테스트하지는 않았 음) 및 PyQt5에서 작동합니다.

최소한의 작업 예. 파이썬 쉘에 복사하고 결과를 얻으십시오.

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

이 기능을 완료하는 데 걸리는 평균 시간이 있습니까? 그만한 가치가 있다면 그냥 관심
DiCaprio

1
@Mrlenny 300ms (전체 코드의 경우), 165ms (코드의 마지막 세 줄).
rominf

-3

시도 해봐:

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

3
이 쓰레기는 무엇입니까? 반 수입은 거기에있어, 쓸모가 while결코 종료 (및 사용 루프 1대신 True)가 if (pb != None):대신의이 if pb:일부 무의미 원시 문자열이 있습니다.
ArtOfWarfare
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.