7 November 2011

Как я делаю скриншоты в Linux

Configuring Linux
В этой заметке хочу увековечить свой велосипед, который я изобрёл для удобного создания скриншотов. Да, я знаю о существовании таких программ как shutter, но все они по тем или иным причинам мне неудобны, а так как был интерес и время, я занялся этой проблемой.



Как работает мой велосипед


Пользователь нажимает PrintScreen, появляется меню, в котором последовательно задаются вопросы:
  1. Сохранить весь экран или только часть (окно)?
  2. Сохранить файл со снимком куда-то на долгую память или сохранить в ненадёжном /tmp?
  3. Ввести имя файла самому, сгенерировать случайное или генерировать по шаблону?
  4. Если по шаблону, предлагается выбрать шаблон или ввести его самому
  5. Выбрать задержку в секундах перед фотографированием
  6. Копировать ли URL опубликованной картинки в буфер
  7. Показать ли диалог с путём к файлу на диске, а также URL картинки

Прорвавшись через эту кучу вопросов, программа:
  1. Уточняет имя файла (если нужно)
  2. Делает скриншот экрана либо ждёт, пока пользователь выделит регион или окно (man scrot)
  3. Если пользователь ввёл имя файла, которое уже существует, выведется подтверждение на перезапись. В случае отмены пользователю придётся самому ещё раз вызвать скрипт (сам он пока не настолько умный, чтобы спросить другое имя файла)
  4. В лог-файл записывается путь к сохранённому файлу и URL опубликованной картинки
  5. В буфер обмена копируется URL скриншота (если надо)
  6. Отображается диалог с путём к файлу на диске и URL опубликованной картинки (если надо)


Скрипт, вызванный без аргументов, будет каждый раз спрашивать вопросы заново. Однако, запомнив ответы пользователя, он их кеширует и записывает в файл (по умолчанию /tmp/screenshot.cache.sh). Если запустить скрипт с аргументом cached, скрипт попытается считать кешированные ответы, и если это удастся, задавать вопросы не будет.

Таким образом, настроив PrintScreen на вызов скрипта с загрузкой кеша, а Win+PrintScreen на вызов без загрузки кеша, я всегда могу изменить настройки, заново ответив на вопросы, после чего фотографировать дальше значительно быстрее.

Disclaimer


Мой дистрибутив ArchLinux, и я пользуюсь openbox в качестве оконного менеджера. У счастливых обладателей KDE/Gnome/Xfce/ваш_вариант процесс установки и использования может отличаться.

Строительные материалы


  1. dmenu (показывать меню)
  2. scrot (скриншотер)
  3. zenity (спрашивать вопросы у пользователя)
  4. xclip (копировать ссылку в буфер обмена)
  5. imagepaste (заливать картинку на image hosting)
  6. скрипт (собрать все компоненты воедино)
  7. terminus-font (шрифты в меню, optional)

Первые четыре программы должны быть (по идее) доступны в репозиториях вашего дистрибутива. Последний пункт опционален. Можете использовать другие шрифты, если terminus вам неугоден. Пятый пункт — моя собственная поделка, смысл которой сводится к заливке картинки на сайты типа ImageShack.us одной командой из командной строки. Сборка этого чуда, вообще говоря, не такая сложная, но описание этого процесса в любом случае выходит за рамки данной заметки, так что Вы вольны заменить этот компонент альтернативными решениями.

Пошаговая инструкция

Вот как выглядела бы установка он начала до конца в моём дистрибутиве.
Установим стандартные пакеты:
$ pacman -S dmenu scrot zenity xclip terminus-font

Сообщим Иксам путь к этим шрифтам (плюс, хорошо бы прописать эту команду в ~/.xinitrc):
$ xset +fp /usr/share/fonts/local/

Считаем, что imagepaste (или аналог) уже установлен, поэтому пропускаем этот шаг.
Устанавливаем скрипт:
$ mkdir ~/bin
$ cd !$
$ wget https://bitbucket.org/balta2ar/screenshot/raw/45ad932db13b/screenshot.sh
$ chmod u+x ./screenshot.sh

Папка ~/bin у меня используется для моих наколенных поделок. В скрипте Вы, вероятно, захотите изменить:
LOG — путь к лог-файлу
FONT — шрифт меню
IMAGEPASTE_CMD — команда для публикации картинки
BASEDIR — базовая директория для тех скриншотов, которые вы захотите сохранять

Не забудьте создать лог-файл:
$ touch /var/log/screenshot.log
$ sudo chown `whoami`:users !$

И последнее, это повесить вызов скрипта на горячую клавишу. Я для этого использовал возможности openbox, а именно obkey для настройки горячих клавиш. Можно, впрочем, сразу залезть в ~/.config/openbox/rc.xml и добавить:
<keybind key="Print">
  <action name="Execute">
    <command>/home/bz/bin/screenshot.sh cached</command>
  </action>
</keybind>
<keybind key="W-Print">
  <action name="Execute">
    <command>/home/bz/bin/screenshot.sh</command>
  </action>
</keybind>


Плюсы

  • своё не пахнет
  • удобно, заточено под свои нужды
  • автоматическая публикация


Минусы

  • установка для красноглазых
  • много компонентов, а хотелось бы один и чтобы всё работало искаропки


Скрипт целиком

#!/bin/bash

init()
{
    ACTIONS[0]="window/region,screen"
    ACTIONS[1]="drop,save"
    ACTIONS[2]="create random,ask,incremental pattern"
    ACTIONS[3]="screenshot-%05d.png"
    ACTIONS[4]="0,5,10,30,60"
    ACTIONS[5]="yes,no"
    ACTIONS[6]="no,yes"

    PROMPT[0]="Capture region"
    PROMPT[1]="Picture file"
    PROMPT[2]="File name"
    PROMPT[3]="File name pattern"
    PROMPT[4]="Delay"
    PROMPT[5]="Copy to clipboard"
    PROMPT[6]="Show links in a dialog"

    IND_CAPTURE_REGION=0
    IND_FILESAVE=1
    IND_FILENAME=2
    IND_PATTERN=3
    IND_DELAY=4
    IND_COPY_CLIPBOARD=5
    IND_SHOW_LINKS=6

    LOG="/var/log/screenshot.log"
    FONT='-xos4-terminus-*-*-*-*-16-*-*-*-*-*-*-*'
    DMENU="dmenu -fn $FONT"
    IMAGEPASTE_CMD="imp"
    SCREENSHOT_CMD="scrot"
    SCREENSHOT_OPTIONS=
    OPTIONS=
    COUNT=${#ACTIONS[*]}
    BASEDIR="/home/`whoami`/pic/screenshot/scrot"
    CACHE="/tmp/screenshot.cache.sh"
    PATTERN_INDEX=0
}

load_cache()
{
    source $CACHE
}

save_cache()
{
    echo -n > $CACHE
    for (( i = 0; i < ${#OPTIONS[*]}; i++ ))
    do
        echo "OPTIONS[$i]=\"${OPTIONS[$i]}\"" >> $CACHE
    done
    echo "PATTERN_INDEX=\"$PATTERN_INDEX\"" >> $CACHE
}

random_filename()
{
    TMP=`mktemp --suffix=.scrot`
    BASE=`basename $TMP`
    FILENAME="$BASEDIR/$BASE.png"
}

ask_filename()
{
    FILENAME=`zenity --entry --text "Enter filename" --entry-text "$BASEDIR/"`
}

set_next_pattern_filename()
{
    FILENAME="$BASEDIR/$(printf ${OPTIONS[$IND_PATTERN]} $PATTERN_INDEX)"
    PATTERN_INDEX=$(($PATTERN_INDEX + 1))

    while [ -e "$FILENAME" ]; do
        FILENAME="$BASEDIR/$(printf ${OPTIONS[$IND_PATTERN]} $PATTERN_INDEX)"
        PATTERN_INDEX=$(($PATTERN_INDEX + 1))
    done
}

ask_options()
{
    for i in $(seq 0 $(($COUNT - 1)))
    do
        # if we are about to ask patern and
        # it wasn't the choise in prev question, continue
        if [ "$i" -eq "$IND_PATTERN" -a "${OPTIONS[$IND_FILENAME]}" != "incremental pattern" ]
        then
            continue
        fi

        OP=`echo ${ACTIONS[$i]} | tr "," "\n" | $DMENU -p "${PROMPT[$i]}"`

        if [ ! -n "$OP" ]; then
            exit 0
        fi

        OPTIONS[$i]=$OP
    done
}

parse_options()
{
    # parse options and ask user questions, if any
    ITEM=${OPTIONS[$IND_CAPTURE_REGION]}
    case "$ITEM" in
        window/region)
            SCREENSHOT_OPTIONS="-b -s"
            ;;
        screen)
            ;;
    esac

    ITEM=${OPTIONS[$IND_FILESAVE]}
    case "$ITEM" in
        save)
            # Dont touch BASEDIR
            ;;
        drop)
            BASEDIR="/tmp"
            ;;
    esac

    ITEM=${OPTIONS[$IND_FILENAME]}
    case "$ITEM" in
        ask)
            ask_filename
            ;;
        "create random")
            random_filename
            ;;
        "incremental pattern")
            set_next_pattern_filename
            ;;
    esac

    ITEM=${OPTIONS[$IND_DELAY]}
    SCREENSHOT_OPTIONS="$SCREENSHOT_OPTIONS -d $ITEM"
}

check_existence()
{
    if [ -e "$FILENAME" ]
    then
        zenity --question --text "File already exists. Overwrite?"
        OVERWRITE=$?
        if [ $OVERWRITE -ne 0 ]
        then
            exit 1
        fi
    fi
}

do_screenshot()
{
    rm -f "$FILENAME"
    mkdir -p `dirname "$FILENAME"`
    $SCREENSHOT_CMD $SCREENSHOT_OPTIONS "$FILENAME"
    CMD="$IMAGEPASTE_CMD $FILENAME"
    URL="`$CMD`"

    echo "$FILENAME -> $URL" >> $LOG
}

copy_to_clipboard()
{
    if [ ${OPTIONS[$IND_COPY_CLIPBOARD]} == "yes" ]
    then
        echo "$URL" | xclip -selection primary
        echo "$URL" | xclip -selection clipboard
    fi
}

show_links()
{
    if [ ${OPTIONS[$IND_SHOW_LINKS]} == "yes" ]
    then
        zenity --info --no-wrap --text "$FILENAME\n$URL"
    fi
}

init
if [ -e "$CACHE" -a "$1" == "cached" ]
then
    load_cache
else
    ask_options
fi
save_cache
parse_options
check_existence
do_screenshot
copy_to_clipboard
show_links

exit 0


UPD 01: Добавлен выбор задержки: 0, 5, 10, 30, 60 секунд.
UPD 02: Добавлено: 1) кеширование ответов пользователя 2) возможность указать инкрементальный паттерн для имени файла.
Tags:bashimagepasteprogrammingreinvented_wheelscreenshot
Hubs: Configuring Linux
+3
31k 33
Comments 45
Popular right now
Administrator Linux. Professional
January 18, 202180,000 ₽OTUS
Безопасность Linux
February 12, 202130,000 ₽OTUS
SEO-специалист
December 7, 202064,900 ₽Нетология
Профессия iOS-разработчик
December 7, 202090,000 ₽SkillFactory