Работаем с pdf из контекстного меню файлового менеджера

de998b974736188ecb1fb8bf55b85267.png

Замечательный файловый менеджер 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 для копирования сценариев в каталоги пользователя.

© Habrahabr.ru