Inspired_Blue
Inspired_Blue

Reputation: 2438

Command line tool to Screenshot multiple monitors separately

Problem-statement

I use scrot to take screenshots, which works perfectly except when I have multiple monitors or displays. In that case scrot joins the screenshots of different monitors into one single output.

From the manpage, scrot supports an option -m:

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

So I imagined the default behavior would be to NOT join them together. However this is not the case. Even without the -m option I get joined screenshots.

I am optimistic that scrot should be able to do this as it support the -u option:

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

which works perfectly fine.

I also checked out another CLI tool called maim - but again I couldn't figure out how to take screenshot of different monitors separately.

So the solution I am excepting should work something like this:

screenshot_command <display_name> # and other options

to screenshot only the display <display_name>.

My attempts at solution so far

maim supports the curios looking option -x:

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

So I tried maim -x 0.0 | xclip -selection clipboard -t image/png, but that doesn't work. I don't know how this option is intended to be used as there isn't enough documentation.

Both scrot and maim also supports the option -s:

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

So I am imagining a very ugly/ hacky solution using xdotool (or similar) to select the desired display and using with the option -s to maim or scrot may do the job. But I would rather not tread this route unless there is no other straight forward solution.

A wild speculation

I wonder if this problem could be because of how I am adding new monitors? I usually add my second display with a command something like this:

xrandr --output eDP-1 --auto --output HDMI-1-4 --auto --right-of eDP-1

So I am wondering, may be to scrot or maim there is only one display. And I imagine so because the output of xdpyinfo | grep -A4 '^screen' with ONE monitor looks like:

$ 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

and with two monitors looks like this:

$ 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

If this is indeed the cause of my problems, then how should I add my second monitor?

Upvotes: 4

Views: 3691

Answers (2)

Inspired_Blue
Inspired_Blue

Reputation: 2438

Using the very useful suggestion from @Arkadiusz Drabczyk I wrote a script that works. I thought I would share the solution.

#!/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

NOTES:

  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.)
    • It takes screenshot every minute starting at the start of next minute using a bunch of sleep commands. This feature could be replaced using cron-job handler if you prefer.
    • The very minimal solution to above question would be convert -crop 1920x1090 +repage "$f".jpg "$f"_%d.jpg. (So you are welcome to strip these bloats, if you prefer). I have added the extra bits anticipating typical usage, so that one may use the code as it is.
  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".
    • My code is intended for use on a fixed set up where, the left monitor is always 1920x1080. You are welcome to make it fancier so that it would work with any setup.
    • Again my code is intended for use on a fixed set up with at most 2 monitors. Again you are welcome to generalize to arbitrary number of monitors.
    • A word of advice if you plan to do the above generalizations so that it would work with any setup: Yes you would need sed/awk/grep or similar to process the output of xrandr -q. But note that xrandr -q can be slow step (as noted here and here). However the output of xrandr -q wouldn't change as often. So to make faster code, you could dump the output of xrandr -q once, every time it's output would change and use the text from the dump for subsequent operations (as illustrated in this this answer) to avoid running xrandr -q on every loop.

Hope that helps. Cheers!

Upvotes: 0

Tiger-222
Tiger-222

Reputation: 7150

Another solution is MSS.

Installation is quite easy (not need for expensive Python modules):

$ python3 -m pip install --user -U mss

It will add a new mss executable you can call anytime.

For instance, to get a screenshot for each monitor, just type:

$ mss
/home/USER/monitor-1.png
/home/USER/monitor-2.png
/home/USER/monitor-3.png

If you want to capture only the first monitor:

$ mss --monitor 1
/home/USER/monitor-1.png

To capture a screenshot of all monitors in one picture (as scrot is doing):

$ mss --monitor -1
/home/USER/monitor-0.png

As of now, the help man shows:

$ 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

Upvotes: 1

Related Questions