Инструмент командной строки для снимка экрана с нескольких мониторов по отдельности

Постановка задачи

Я использую scrot для создания снимков экрана, и это работает отлично, за исключением случаев, когда у меня несколько мониторов или дисплеев. В этом случае scrot объединяет снимки экрана с разных мониторов в один вывод.

На странице руководства 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.

который отлично работает.

Я также проверил другой инструмент CLI под названием maim, но снова не смог понять, как делать снимки экрана разных мониторов по отдельности.

Итак, решение, которое я исключаю, должно работать примерно так:

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, но это не сработало. Я не знаю, как эта опция предназначена для использования, поскольку документации недостаточно.

И scrot, и maim также поддерживают опцию -s:

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

Итак, я представляю себе очень уродливое/хакерское решение, использующее xdotool (или подобное) для выбора нужного дисплея, а использование с параметром -s to 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

Если это действительно причина моих проблем, то как мне добавить второй монитор?


person Inspired_Blue    schedule 26.09.2019    source источник
comment
Вы можете обрезать выходной снимок экрана с помощью convert, как описано здесь: askubuntu.com/a/647272/386622   -  person Arkadiusz Drabczyk    schedule 26.09.2019
comment
Мой ответ хорош как есть, но, как вы упомянули, проблема может быть в другом. В вашей команде xrandr есть 2 --oputput. Не могли бы вы удалить один и посмотреть, есть ли у вас большой экран?   -  person Tiger-222    schedule 28.09.2019


Ответы (2)


Другое решение — 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
person Tiger-222    schedule 28.09.2019

Используя очень полезное предложение от @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. The above script does more than what I originally asked for:
    • It ensures at most one instance of this script is running (first code paragraph) which is borrowed from this stack-overflow post. (As pointed out by @tripleee in the comments this is not a good practice. Please be mindful of it.)
    • Он делает снимок экрана каждую минуту, начиная с начала следующей минуты, используя группу sleep commands. Эту функцию можно заменить с помощью обработчика заданий cron, если хотите.
    • Самым минимальным решением вышеуказанного вопроса будет convert -crop 1920x1090 +repage "$f".jpg "$f"_%d.jpg. (Так что, если хотите, можете раздеть эти вздутия). Я добавил дополнительные биты, предвосхищая типичное использование, чтобы можно было использовать код как есть.
  2. Here is how to do other things, if you want to:
    • You could replace 1920x1080 with whatever is the dimension of your left monitor. You could find these dimensions using xrandr -q | grep " connected".
    • Мой код предназначен для использования в фиксированной настройке, где левый монитор всегда 1920x1080. Вы можете сделать его более привлекательным, чтобы он работал с любой настройкой.
    • Опять же, мой код предназначен для использования на фиксированной установке не более чем с двумя мониторами. Опять же, вы можете обобщить произвольное количество мониторов.
    • Совет, если вы планируете сделать вышеуказанные обобщения, чтобы они работали с любой настройкой: Да, вам понадобится sed/awk/grep или что-то подобное для обработки вывода xrandr -q. Но обратите внимание, что xrandr -q может быть медленным шагом (как указано здесь и здесь). Однако вывод xrandr -q не будет меняться так часто. Таким образом, чтобы сделать код быстрее, вы можете выводить вывод xrandr -q один раз, каждый раз, когда его вывод будет меняться, и использовать текст из дампа для последующих операций (как показано на этом этот ответ), чтобы избежать запуска xrandr -q в каждом цикле.

Надеюсь, это поможет. Ваше здоровье!

person Inspired_Blue    schedule 06.10.2019
comment
Убийство других экземпляров этого скрипта с полным отказом ужасно враждебно. Просто выйдите из этого скрипта с сообщением об ошибке и оставьте конкурента работающим. - person tripleee; 06.10.2019
comment
Это дело вкуса. Вы навязываете / администрируете свою эстетику дизайна здесь. - person Inspired_Blue; 06.10.2019
comment
Эта эстетика связана с избеганием неприятных сюрпризов и достаточно универсальна. Действия на расстоянии — это проблема, независимо от того, вызваны ли они goto, глобальными переменными или мошенническими процессами, убивающими вас. - person tripleee; 06.10.2019
comment
Понимаю. Я согласен. Я бы добавил примечание по этому поводу в решение. - person Inspired_Blue; 06.10.2019