多显示器分别截屏的命令行工具

3

问题陈述

我使用scrot来截屏,它可以完美地工作,但当我有多个显示器时就会出现问题,此时scrot会将不同显示器的屏幕截图合并成一个输出。

从man页面得知,scrot支持一个选项-m

-m, --multidisp
        For multiple heads, grab shot from each and join them together.

因此,我认为默认情况下不会将它们连接在一起。然而,事实并非如此。即使没有-m选项,我仍然得到了连接的截图。

我很乐观地认为scrot应该能够做到这一点,因为它支持-u选项:

-u, --focused
        Use the currently focused window.

这个工具完美地运作。

我也尝试了另一个名为maim的CLI工具——但是我仍然不知道如何单独截取不同显示器的截图。

所以,我期望的解决方案应该像这样运作:

screenshot_command <display_name> # and other options

截屏只显示 <display_name>

我迄今为止尝试的解决方案

maim 支持这个奇特的选项 -x:

-x, --xdisplay=hostname:number.screen_number
          Sets the xdisplay to use.

我尝试过 maim -x 0.0 | xclip -selection clipboard -t image/png,但这并不起作用。由于文档不足,我不知道如何使用这个选项。

scrotmaim 都支持选项 -s

-s, --select
        Interactively select a window or rectangle with the mouse.

我设想了一种非常丑陋/拙劣的解决方案,使用xdotool(或类似工具)选择所需的显示器,并使用-s选项来执行maim或scrot,可能能够解决问题。但我不想走这条路,除非没有其他简单直接的解决方案。
一个大胆的猜测:
我想知道这个问题是否是因为我添加新监视器的方式不正确?我通常会使用类似以下命令添加第二个显示器:
xrandr --output eDP-1 --auto --output HDMI-1-4 --auto --right-of eDP-1

所以我在想,也许使用 scrot 或者 maim 只有一个显示器。我这样想是因为只有一个监视器时,xdpyinfo | grep-A4 '^screen' 的输出看起来像:

$ xdpyinfo | grep -A4 '^screen'
screen #0:
  dimensions:    1920x1080 pixels (506x285 millimeters)
  resolution:    96x96 dots per inch
  depths (7):    24, 1, 4, 8, 15, 16, 32
  root window id:    0x1ba

双屏显示的效果如下,两个显示器:

$ xdpyinfo | grep -A4 '^screen'
screen #0:
  dimensions:    3280x1080 pixels (865x285 millimeters)
  resolution:    96x96 dots per inch
  depths (7):    24, 1, 4, 8, 15, 16, 32
  root window id:    0x1ba

如果这确实是我的问题所在,那么我应该如何添加我的第二个显示器?


1
您可以按照此处的说明(https://askubuntu.com/a/647272/386622),使用“convert”裁剪输出截图。 - Arkadiusz Drabczyk
我的答案本身很好,但正如你所提到的,问题可能出在其他地方。在你的xrandr命令中,有2个--output。你能否删除一个并查看是否仍然有一个大屏幕? - Tiger-222
2个回答

1
另一个解决方案是 MSS
安装非常简单(不需要昂贵的 Python 模块):
$ python3 -m pip install --user -U mss

它将添加一个新的mss可执行文件,您随时可以调用。
例如,要为每个监视器获取屏幕截图,只需键入:
$ mss
/home/USER/monitor-1.png
/home/USER/monitor-2.png
/home/USER/monitor-3.png

如果您只想捕获第一个显示器:
$ mss --monitor 1
/home/USER/monitor-1.png

要捕获所有监视器的屏幕截图(就像scrot所做的那样):
$ mss --monitor -1
/home/USER/monitor-0.png

截至目前,帮助文档显示:
$ mss --help
usage: mss [-h] [-c COORDINATES] [-l {0,1,2,3,4,5,6,7,8,9}] [-m MONITOR]
           [-o OUTPUT] [-q] [-v]

optional arguments:
  -h, --help            show this help message and exit
  -c COORDINATES, --coordinates COORDINATES
                        the part of the screen to capture: top, left, width,
                        height
  -l {0,1,2,3,4,5,6,7,8,9}, --level {0,1,2,3,4,5,6,7,8,9}
                        the PNG compression level
  -m MONITOR, --monitor MONITOR
                        the monitor to screen shot
  -o OUTPUT, --output OUTPUT
                        the output file name
  -q, --quiet           do not print created files
  -v, --version         show program's version number and exit

0

使用@Arkadiusz Drabczyk提供的非常有用的建议,我编写了一个可行的脚本。我想分享这个解决方案。

#!/bin/bash

# to have at most one instance of this script running...
script_name=${BASH_SOURCE[0]}
for pid in $(pidof -x $script_name); do
    if [ $pid != $$ ]; then
        kill -9 $pid
    fi 
done

loc="/path/to/folder/"

# take screenshots every minute starting at next minute...
s=$((60 - $(date +%-S)))
sleep "$s"s

while true
do
    f=$(date +'%Y%m%d_%H%M%S')
    scrot -q 20 "$f".jpg
    n=$(xrandr --listmonitors | head -n 1 | sed -e "s/Monitors: //g")
    if (( n == 2 )); then
    convert -crop 1920x1080 +repage "$f".jpg "$f"_%d.jpg
    mv -t "$loc" "$f"_0.jpg "$f"_1.jpg
    rm "$f".jpg
    else
    mv -t "$loc" "$f".jpg
    fi
    s=$((60 - $(date +%-S)))
    sleep "$s"s
done

注意事项:

  1. 上述脚本做了比我最初要求的更多事情:
    • 它确保此脚本最多只运行一个实例(第一个代码段),这是从stack-overflow帖子中借鉴的。(正如@tripleee在评论中指出的那样,这不是一个好习惯。请注意这一点。)
    • 它使用一堆sleep命令从下一分钟开始每分钟截取屏幕截图。如果您愿意,可以使用cron-job handler替换此功能。
    • 上述问题的非常简单的解决方案是convert -crop 1920x1090 +repage "$f".jpg "$f"_%d.jpg。(因此,如果您愿意,可以去掉这些臃肿的部分)。我添加了额外的内容,预期典型用法,以便可以直接使用代码。
  2. 如果您想要执行其他操作,请按照以下步骤进行:
    • 您可以将1920x1080替换为左侧监视器的尺寸。您可以使用xrandr -q | grep " connected"查找这些尺寸。
    • 我的代码旨在用于固定设置,其中左侧监视器始终为1920x1080。您可以使其更加复杂,以便适用于任何设置。
    • 同样,我的代码旨在用于最多2个监视器的固定设置。您也可以将其推广到任意数量的监视器。
    • 如果您计划进行上述泛化,以便它适用于任何设置,请注意以下建议:是的,您需要使用sed/awk/grep或类似工具来处理xrandr -q的输出。但请注意,xrandr -q可能是一个缓慢的步骤(如herehere所述)。然而,xrandr -q的输出不会经常更改。因此,为了使代码更快,您可以在每次输出更改时转储xrandr -q的输出,并使用转储文本进行后续操作(如this answer中所示),以避免在每个循环中运行xrandr -q
希望能对你有所帮助。祝好!

1
彻底终止此脚本的其他实例是极其不友好的。只需使用错误消息退出此脚本并让竞争者继续运行即可。 - tripleee
这是一个品味问题。你在这里强加/管理你的设计美学。 - Inspired_Blue
1
这些美学与避免不愉快的惊喜有关,而且是相当普遍的。无论是由于“goto”,全局变量还是流氓进程杀死您,远距离操作都是一个问题。 - tripleee
我明白了。我同意。我会在解决方案中添加一条注释来说明这一点。 - Inspired_Blue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接