Замечательный файловый менеджер Dolphin всем хорош. И две панели, и разнообразные контекстные меню ускоряющие обработку всевозможных команд и заданий. Но что делать если нужно простенько и быстро собрать несколько одностраничных pdf-файлов? Не устанавливать же из-за этого тяжеловесное ПО, которым в последствии пользоваться крайне редко. Конечно же нет. Просто расширим возможности нашего менеджера, добавив пару пунктов в контекстное меню. Тем более, что сделать это совсем не сложно. Но сначало нужно написать пару сценариев для этой самой обработки pdf-файлов. И так, приступим.

Работаем с pdf-файлами

Для обработки файлов будем использовать консольную программу pdftk. Поскольку сценарий будет встраиваться в контекстное меню, для отображения информации об ошибках, ходе выполнения будем использовать утилиту zenity. Также нам понадобятся всплывающие сообщения, за них будет отвечать notify-send.

pdfmark - объединение pdf-файлов и добавление закладок

Раз скрипту передаются какие-то аргументы, то нужно проверять что и сколько было передано через командную строку. А раз аргументов не так много то и проверку пишем в две строчки. Первой проверяем вызов справки по ключам -h и --help. Второй строчкой проверим только количество переданных файлов, один файл нет смысла обрабатывать.

Далее создаем временную директорию и уже в ней создаем файл закладок для будущего объединеного pdf-файла. Добавим заголовок документа по имени директории из которой объединяем файла. В качестве имени автора документа используем имя пользователя. Добавляем закладки по именам файлов в файл закладок. Производим объединение, добавляем закладки, проверяем успешность операции по наличию итогового файла и выводим соответствующие сообщения. Перед выходом удаляем временную директорию.

pdfmark: закладки и объединение
{
    NumberPage=1
    echo "InfoBegin"
    echo "InfoKey: Title"
    echo "InfoValue: ${WorkDir}"
    echo "InfoBegin"
    echo "InfoKey: Author"
    echo "InfoValue: ${USER^}"
    echo "NumberOfPages: ${#FileList[@]}"
    for BookMark in "${MarkList[@]}"; do
        echo "BookmarkBegin"
        echo "BookmarkTitle: ${BookMark}"
        echo "BookmarkLevel: 1"
        echo "BookmarkPageNumber: ${NumberPage}"
        ((NumberPage += 1))
    done
} >>"${TmpDir}"/file.info

# объединить выбранные документы и добавить закладки
(pdftk "${@}" cat output "${TmpDir}"/"${WorkDir}".pdf && pdftk "${TmpDir}"/"${WorkDir}".pdf update_info "${TmpDir}"/file.info output "${WorkDir}.pdf") | zenity --progress --title="${msg_title}" --text="${msg_progress}" --pulsate --width=500 --no-cancel --auto-close --auto-kill

pdf_service_menu - меню для обработки pdf файлов

Второй сценарий будет выполнять больше операций с pdf файлами. Список доступных операций:

  • burst - позволяет разобрать весь документ на станицы;

  • extract - извлекает указанные страницы из документа;

  • remove - удаляет диапазон страниц из документа;

  • cat - объединяет документы;

  • add - добавляет выбранные документы, в порядке их выбора;

  • stamp - ставит штамп на страницы документа;

  • pdf2jpg - позволяет преобразовать страницы документа в jpg;

  • info - отображает информацию о документе;

Здесь в качестве графических диалогов используем kdialog. По сути тот же zenity но ближе к kde. И подойдет намного лучше по оформлению к Dolphin.

Простые функции такие как burst, extract и подобные описывать нет смысла. Там все просто и понятно.

Интерес представляет функция remove которая удаляет диапазон страниц из документа. pdfkt не поддерживает удаление страниц. Но зато может извлекать страницы как по одной так и диапазон страниц. Этот трюк и используем для удаления диапазона страниц.

В первую очередь нужно определить диапазон страниц. Запрашиваем у пользователя через kdialog границы диапазона. И определяем номер последней страницы в документе. Он нужен чтобы не выйти за границы документа.

pdf_service_menu: kdialog - диапазоны страниц
msg_remove_title="Удалить страницы..."
msg_remove_range="Диапазон страниц для удаления из документа\n\"${filename}\"\n\nИнструкция:\n\nКлючевое слово \"end\" может использоваться, чтобы сослаться на заключительную\nстраницу документа, вместо номера страницы. Сошлитесь на одну страницу, опуская\nномер конечной страницы.\n\nПримеры:\n\n2 - удалить страницу 2;\n3-45 - удалить страницы с 3 по 45;\n5-end - удалить страницы с 5 по последнюю.\n\nВведите диапазон страниц для удаления:"

range="$(kdialog --icon viewpdf --title "${msg_remove_title}" --inputbox "${msg_remove_range}" "2-end")" || return 1

. . .

totalpages="$(pdftk "${@}" dump_data | grep "NumberOfPages" | cut -d" " -f 2-)"

Затем проверяем начальный и конечный диапазоны страниц. Нам необходимо убедиться что не выходим за границы документа.

pdf_service_menu: диапазоны страниц
first="${range%-*}"
if [ "${first}" = "end" ]; then
	first="${totalpages}"
else
	first="${first//[^[0-9]]/}"
	if [ -z "${first}" ]; then
		first=1
	else
		if [ "${first}" -eq 0 ]; then
			first=1
		elif [ "${first}" -gt "${totalpages}" ]; then
			first="${totalpages}"
		fi
	fi
fi

. . .

last="${range#*-}"
if [ "${last}" = "end" ]; then
	last="${totalpages}"
else
	last="${last//[^[0-9]]/}"
	if [ -z "${last}" ]; then
		last="${totalpages}"
		elif [ "${last}" -lt "${first}" ]; then
			last="${first}"
		elif [ "${last}" -gt "${totalpages}" ]; then
		last="${totalpages}"
	fi
fi

После всех подготовительных операций определяем границы диапазнов для извлечения страниц.

pdf_service_menu: диапазоны страниц для извлечения
# определяем диапазон страниц range1
if [ "${first}" -eq 1 ]; then
		range1=''
	elif [ "${first}" -eq 2 ]; then
		range1="1"
		else
			range1="1-$((first - 1))"
fi
# определяем диапазон страниц range2
if [ "${last}" -eq "${totalpages}" ]; then
		range2=''
	elif [ "${last}" -eq "$((totalpages - 1))" ]; then
		range2="${totalpages}"
	else
		range2="$((last + 1))-${totalpages}"
fi

Далее проверяем что не удаляем все страницы из документа, указываем куда сохранить итоговый файл. И выполняем извлечение страниц в найденых диапазонах.

Подключаем сценарии в контекстное меню

Сценарии готовы осталось подключить их в контекстное меню Dolphin. Пишем простенький desktop файл в котором расписываем наши функции и бросаем его в директорию ServiceMenus.

Заключение

Все сценарии и функции писались исключительно из задач которые чаще всего приходилось решать. stamp был добавлен позже в экспериментальных целях так и остался. info - тоже особой функциональности не придает. А все остальные функции используются достаточно часто и востребованы. Перед использованием данных сценариев нужно убедиться что установлены все пакеты используемые в сценариях. pdftk к примеру должен устанавливаться отдельно.

Все сценарии и desktop файл доступны на github. Там же находится простенький скрипт install.sh для копирования сценариев в каталоги пользователя.

Комментарии (5)


  1. economist75
    22.09.2022 09:57

    Хорошие скрипты. Для любителей файлового менеджера Nautilus (он, вдобавок, умеет отображать мета-свойства файла в отдельных столбцах: автора, комментарий, ключевые слова, название документа итд) - так вот для Nautilus можно писать подобные PDF-скрипты на Python, с интеграцией в меню. Возможно их уже написано много, но написать свой под свой МФУ/документооборот/бизнес-процесс - не только зачетно, но и порой остро необходимо. В экосистеме Python много свободных PDF-либ для любых манипуляций:

    • segno - лучшая вставка QR и DataMatrix-кодов в готовый PDF

    • PyPDF2 - простая нумерация страниц и др. операции

    • pypdftk - разрезка/склейка/поворот/закладки/метаинформация

    • PyMuPDF - вообще почти все мыслимые манипуляции


    1. VlaSard
      22.09.2022 10:33

      Есть написанные и на Python с использованием pikepdf. Но смешивать shell и Python как-то не хочется.


      1. VlaSard
        22.09.2022 11:26

  1. Writer
    22.09.2022 12:17
    +1

    Если речь о Dolphin и KDE, то совершенно непонятно, зачем вам Zenity в первом примере, надо было везде уведомления через kdialog выводить. Ну или использовать Qarma.

    Тема сервисных меню в KDE не раскрыта - а это интереснейший момент, про который мало кто пишет.

    Куски скриптов без заголовков, без контекста, с обрывочным комментарием - ну такое...

    Так себе статья, уж извините.


    1. VlaSard
      22.09.2022 14:13

      kdialog лучше работает с диалоговыми окнами выбора. zenity лучше выглядит при выводе сообщений. Если память не изменяет то выбор делался из возможностей для той или иной задачи и оформления окон. Что касается "кусков скриптов" в статью не планировалось добавлять тексты в полном объеме. Для просмотра всего скрипта приведена ссылка на github. Реп публичный. Здесь показал как можно работать с pdf не устанавливая специализированного ПО.

      По поводу "так себе статья" кому то нравится кому то нет.

      Qarma это клон Zenity. Приводить его против Zenity такой себе вариант.