Take a screenshot via a Python script on Linux

后端 未结 15 1005
暖寄归人
暖寄归人 2020-11-22 11:50

I want to take a screenshot via a python script and unobtrusively save it.

I\'m only interested in the Linux solution, and should support any X based environment.

相关标签:
15条回答
  • 2020-11-22 12:27

    for ubuntu this work for me, you can take a screenshot of select window with this:

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

    to transform pixbuf into array

    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 讨论(0)
  • 2020-11-22 12:31

    Try it:

    #!/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."
    
    0 讨论(0)
  • 2020-11-22 12:38

    There is a python package for this Autopy

    The bitmap module can to screen grabbing (bitmap.capture_screen) It is multiplateform (Windows, Linux, Osx).

    0 讨论(0)
  • 2020-11-22 12:40

    This works without having to use scrot or 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."
    

    Borrowed from http://ubuntuforums.org/showpost.php?p=2681009&postcount=5

    0 讨论(0)
  • 2020-11-22 12:40
    import ImageGrab
    img = ImageGrab.grab()
    img.save('test.jpg','JPEG')
    

    this requires Python Imaging Library

    0 讨论(0)
  • 2020-11-22 12:41

    Just for completeness: Xlib - But it's somewhat slow when capturing the whole screen:

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

    One could try to trow some types in the bottleneck-files in PyXlib, and then compile it using Cython. That could increase the speed a bit.


    Edit: We can write the core of the function in C, and then use it in python from ctypes, here is something I hacked together:

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

    And then the 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()
    
    0 讨论(0)
提交回复
热议问题