我正在使用屏幕截图作为 GUI 软件的回归测试。在部署每个新版本之前,都会针对旧版本和新版本运行一系列自动任务,在两种情况下,每个命令之后都会生成屏幕截图,并比较结果。ImageMagick 的导入命令在这方面一直运行良好。
最近我添加了右键菜单。不幸的是,import -window 'id'
无法捕获这些菜单。
Ubuntu 上的哪些命令行工具可以截取一个窗口以及其上的所有窗口的屏幕截图?
也就是说,哪些工具可以不截取与窗口 ID 对应的窗口的屏幕截图,截取整个屏幕的屏幕截图并将其截断到给定窗口的边界?
我无法用列出的任何工具以简单的方式获得此结果截屏的终端命令是什么?。
答案1
使用shutter
和wmctrl
,编辑版本这个脚本它的功能与你描述的完全一样:截取该地区,特定窗口将覆盖在您的屏幕上,无论该窗口是否(部分)位于其他窗口下方以及如何位于其他窗口下方。
这玛吉窗口周围要包含在屏幕截图中的区域是任意的;如果愿意,将其设置为零。
在实践中
Inkscape
我的屏幕上有一个窗口,其 id 为0x0520000e
,被几个gedit
窗口部分覆盖。我使用窗口 ID 和
px
窗口周围的边缘(在 中)作为参数来运行脚本:python3 <script> 0x0520000e 10 10 10 10
(窗口左侧/右侧/顶部/底部的
10 10 10 10
边距在哪里。设置为则图像中没有边距)px
0
结果:
剧本
#!/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])
如何使用
该脚本使用
Shutter
和wmctrl
: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 作为参数,脚本在
wmctrl
(wmctrl -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
需要imagemagick
wmctrl
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
}