编辑

编辑

我正在使用屏幕截图作为 GUI 软件的回归测试。在部署每个新版本之前,都会针对旧版本和新版本运行一系列自动任务,在两种情况下,每个命令之后都会生成屏幕截图,并比较结果。ImageMagick 的导入命令在这方面一直运行良好。

最近我添加了右键菜单。不幸的是,import -window 'id'无法捕获这些菜单。

Ubuntu 上的哪些命令行工具可以截取一个窗口以及其上的所有窗口的屏幕截图?

也就是说,哪些工具可以不截取与窗口 ID 对应的窗口的屏幕截图,截取整个屏幕的屏幕截图并将其截断到给定窗口的边界

我无法用列出的任何工具以简单的方式获得此结果截屏的终端命令是什么?

答案1

使用shutterwmctrl,编辑版本这个脚本它的功能与你描述的完全一样:截取该地区,特定窗口将覆盖在您的屏幕上,无论该窗口是否(部分)位于其他窗口下方以及如何位于其他窗口下方。

玛吉窗口周围要包含在屏幕截图中的区域是任意的;如果愿意,将其设置为零。

在实践中

  • Inkscape我的屏幕上有一个窗口,其 id 为0x0520000e,被几个gedit窗口部分覆盖。
  • 我使用窗口 ID 和px窗口周围的边缘(在 中)作为参数来运行脚本:

    python3 <script> 0x0520000e 10 10 10 10 
    

    (窗口左侧/右侧/顶部/底部的10 10 10 10边距在哪里。设置为则图像中没有边距)px0

    结果:

    在此处输入图片描述

剧本

#!/usr/bin/env python3
import subprocess
import time
import sys

"""
On different window managers, the window geometry as output of wmctrl differs slightly.
The "deviation" should compensate these differences. Most likely appropriate (tested) settings:
Unity: 0, Gnome: -36, Xfce (Xubuntu): -26, KDE (Kubuntu): 0
"""
#---
deviation = 0
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
time.sleep(0.5)
# targeted window
target = sys.argv[1]; arg = sys.argv[2:]
f_data = [l.split() for l in get("wmctrl -lG").splitlines() if target in l][0][2:6]
xt_data = get("xprop -id "+target).split()
xt_i = xt_data.index("_NET_FRAME_EXTENTS(CARDINAL)")
xt = [int(n.replace(",", "")) for n in xt_data[xt_i+2:xt_i+6]]
# set data for screenshot command
x = str(int(f_data[0])-int(arg[0])-xt[0])
y = str(int(f_data[1])-int(arg[2])-xt[2]+deviation)
w = str(int(f_data[2])+int(arg[0])+int(arg[1])+xt[0]+xt[1])
h = str(int(f_data[3])+int(arg[3])+int(arg[2])+xt[2]+xt[3])

command = "shutter -s="+(",").join([x,y,w,h])+" -e"
subprocess.call(["/bin/bash", "-c", command])

如何使用

  • 该脚本使用Shutterwmctrl

    sudo apt-get install wmctrl shutter
    
  • 将下面的脚本复制到一个空文件中,并将其保存为custom_screenshot.py

  • 通过命令运行:

    python3 /path/to/custom_screenshot.py <window_id> <left> <right> <top> <bottom>
    

    哪里<left> <right> <top> <bottom>是你想要保留在窗口周围图像中的边缘,比如这个答案。

    示例命令:

    python3 /path/to/custom_screenshot.py 0x0520000e 20 20 20 20
    

解释

  • 在 中Shutter,可以对桌面上指定区域的屏幕进行截图。

  • 使用窗口 id 作为参数,脚本在wmctrlwmctrl -lG准确地说)和(例如xprop -id <window_id>在行中)的输出的帮助下查找窗口的确切位置。_NET_FRAME_EXTENTS(CARDINAL) = 0, 0, 28, 0

  • 随后,从找到的区域截取一张带有任意边缘的屏幕截图。

笔记

剧本才不是覆盖现有屏幕截图。新屏幕截图命名为:

outputfile_1.png
outputfile_2.png
outputfile_3.png

等等...


编辑

由于您在评论中提到速度是一个问题:

基于这个脚本,如果我们使用完全相同的技巧,但使用Scrot而不是Shutter,我们可以跳过sleep 0.5并使其成为很多快点:

剧本

#!/usr/bin/env python3
import subprocess
import sys
import os

"""
On different window managers, the window geometry as output of wmctrl differs slightly.
The "deviation" should compensate these differences. Most likely appropriate (tested) settings:
Unity: 0, Gnome: -36, Xfce (Xubuntu): -26, KDE (Kubuntu): 0
"""
#---
deviation = 0
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
# targeted window
target = sys.argv[1]; arg = sys.argv[2:]
f_data = [l.split() for l in get("wmctrl -lG").splitlines() if target in l][0][2:6]
xt_data = get("xprop -id "+target).split()
xt_i = xt_data.index("_NET_FRAME_EXTENTS(CARDINAL)")
xt = [int(n.replace(",", "")) for n in xt_data[xt_i+2:xt_i+6]]
# set data for screenshot command
x = str(int(f_data[0])-int(arg[0])-xt[0])
y = str(int(f_data[1])-int(arg[2])-xt[2]+deviation)
w = str(int(f_data[2])+int(arg[0])+int(arg[1])+xt[0]+xt[1])
h = str(int(f_data[3])+int(arg[3])+int(arg[2])+xt[2]+xt[3])

# setting default directories / filenames
home = os.environ["HOME"]
temp = home+"/"+".scrot_images"
img_in = temp+"/in.png"
# if you prefer, you can change the two line below:
output_directory = home+"/"+"scrot_images" # output directory
filename = "outputfile"                    # filename
# creating needed directories
for dr in [temp, output_directory]:
    if not os.path.exists(dr):
        os.mkdir(dr)
# creating filename (-number) to prevent overwriting previous shots
n = 1
while True:
    img_out = output_directory+"/"+filename+"_"+str(n)+".png"
    if os.path.exists(img_out):
        n = n+1
    else:
        break
# Take screnshot, crop image
subprocess.call(["scrot", img_in])
subprocess.Popen(["convert", img_in, "-crop", w+"x"+h+"+"+x+"+"+y, "+repage", img_out])

使用

使用方法与第一个脚本完全相同,只是:

  • 此脚本scrot需要imagemagickwmctrl

    sudo apt-get install imagemagick wmctrl scrot
    
  • 图像将存储在~/scrot_images

解释

虽然第一个脚本使用命令行选项来Shutter截取桌面的特定部分,但Scrot不支持该选项。它只截取整个屏幕

但是,我们可以结合 的imagemagick选项来截取图像,以及在第一个脚本中使用的方法来查找窗口的确切坐标,并相应地裁剪图像。
由于Scrot非常轻量且快速,即使与imagemagick的裁剪操作相结合,我们也可以非常快速地对窗口区域进行屏幕截图。

还是不够快?

不确定是否有必要,但只要稍微重写一下(见下面的脚本),就可以先拍摄整个系列,从而更快地完成一系列拍摄。然后(之后)进行裁剪。假设窗口会保持其位置,这将节省大量时间:

  • 仅拍摄Scrot(无裁剪):

    real    0m0.263s
    user    0m0.205s
    sys     0m0.037s
    
  • 拍摄,包括裁剪:

    real    0m0.363s
    user    0m0.293s
    sys     0m0.040s
    

连环射击

最后,作为制作一系列截图的示例,下面的脚本,如EDIT中所建议的。
这一个第一的连续拍摄所有图像,然后一次对所有创建的图像进行裁剪。

使用第二个脚本,但使用一个额外的论点:一行中芽的数量,例如:

python3 /path/to/custom_screenshot.py 0x0520000e 0 0 0 0 20

0x0520000e连续截取 20 张窗口截图(可能数百张),窗口周围没有边距。

剧本

#!/usr/bin/env python3
import subprocess
import sys
import os

"""
On different window managers, the window geometry as output of wmctrl differs slightly.
The "deviation" should compensate these differences. Most likely appropriate (tested) settings:
Unity: 0, Gnome: -36, Xfce (Xubuntu): -26, KDE (Kubuntu): 0
"""
#---
deviation = 0
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
# targeted window
target = sys.argv[1]; arg = sys.argv[2:]
f_data = [l.split() for l in get("wmctrl -lG").splitlines() if target in l][0][2:6]
xt_data = get("xprop -id "+target).split()
xt_i = xt_data.index("_NET_FRAME_EXTENTS(CARDINAL)")
xt = [int(n.replace(",", "")) for n in xt_data[xt_i+2:xt_i+6]]
# set data for screenshot command
x = str(int(f_data[0])-int(arg[0])-xt[0])
y = str(int(f_data[1])-int(arg[2])-xt[2]+deviation)
w = str(int(f_data[2])+int(arg[0])+int(arg[1])+xt[0]+xt[1])
h = str(int(f_data[3])+int(arg[3])+int(arg[2])+xt[2]+xt[3])
# setting default directories / filenames
home = os.environ["HOME"]
temp = home+"/"+".scrot_images"
# if you prefer, you can change the two line below:
output_directory = home+"/"+"scrot_images" # output directory
filename = "outputfile"                    # filename
# creating needed directories
for dr in [temp, output_directory]:
    if not os.path.exists(dr):
        os.mkdir(dr)
# do the shooting
t = 0; l = []; shots = int(sys.argv[6])
while t < shots:
    img_temp = temp+"/"+str(t)+"in.png"
    l.append(img_temp)
    # reading arguments,arranging commands to perform
    subprocess.call(["scrot", img_temp])
    t += 1
# do the cropping on all images in a row
for img in l:
    n = 1
    while True:
        img_out = output_directory+"/"+filename+"_"+str(n)+".png"
        if os.path.exists(img_out):
            n = n+1
        else:
            break
    subprocess.call(["convert", img , "-crop", w+"x"+h+"+"+x+"+"+y, "+repage", img_out])

答案2

import与选项一起使用-screen,例如

import -screen -window 'id' test.png

答案3

阅读man import。在我的(实际上是在d 的.bashrc文件中) 中,我有: source.bashrc

alias tshhmmss='date +%y%b%d-%H%M%S'
screenshot ()
{
   import -window root ~/var/screenshot/$(tshhmmss)_screendump.png
}

相关内容