С чего всё началось
Началось всё с лени. Лень бывает продуктивная и не очень, в моём случае, похоже — первое.
Недавно прикупил на «Литресе» книжку Нассима Талеба «Антихрупкость». Скачал, закинул на читалку, да так до неё и не добрался, то жена утащит своё почитать, то ребёнок… А тут в рассылке прилетела вот эта статья «Лучший подарок – книга. Делаем красивый переплет». Посмотрел, всё вроде красиво, только вот под рукой не оказалось машины с «Форточками», ну не пользуемся мы ими, а запускать эти WordPage-ы через прокладку типа Wine или в Qemu как-то некомильфо. Однако у меня имеется возможность распечатать книженцию и нормально обрезать (мини-типография на первом этаже дома, в котором я живу) в нужный формат. Сие значит, что следует использовать возможности подручных средств.
Идея
У себя в конторе я уже с полгодика использую небольшой bash-скрипт для сборки разрозненных PDF-ников воедино и формирования единой структуры проектной документации. Значит, один кандидат на запчасти есть.
Собственно идея состояла в том, чтобы в определённой последовательности разложить отдельные странички по тетрадкам произвольного объёма, кратного 4. Если внимательно посмотреть, то один тетрадный лист содержит именно 4, а не три или пять страниц, причём страницы расположены в определённом порядке на листе, правда, это я потом допетрил, а пока было так, как есть, а именно (для 48-страничной тетради):
Пары страниц | зависимость |
---|---|
1-48 | m=(1) n=(48) |
2-47 | m=(1+1) n=(48-1) |
3-46 | m=(1+2) n=(48-2) |
... | ... |
24-25 | m=(1+23) n=(48-23) |
Сие значит, что, во-первых, следует книгу разбить на i страниц, затем на j тетрадей по k страниц каждая, затем каждую тетрадь разбить на пары страниц, которые разместить на листах, которые собрать в единые файлы тетрадей, который разместить рядом с исходным PDF-ником. Ф-ф-фу, еле сформулировал…
В общем-то зависимость простая, первая страница листа — это a+b, а последняя — k-b, где a — порядковый номер тетради, причём 0<a<j, а b — порядковый номер парной страницы, причём 0<b<k/2. Т.е. это цикл for ((b=0; b<k/2; b++)) в котором и следует обрабатывать все эти странички.
Сей цикл мы запихиваем в другой, который пробегает по тетрадкам for ((a=0; a<j; a++)).
Попутно выяснилось, что часть кода лучше вынести в отдельные функции, да и bash делит всё нацело, а это значит, что нужно дорабатывать сборку остатков страниц, что оказалось примитивно. На закуску выяснилось, что порядок страниц на листах не совсем тот, как был в табличке выше, а вот такой:
Пары страниц | зависимость |
---|---|
48-1 | n=(48) m=(1) |
2-47 | m=(1+1) n=(48-1) |
46-3 | n=(48-2) m=(1+2) |
... | ... |
Что решилось довольно просто:
if [ "`expr $b % 2`" -gt "0" ] then #Если ПАРА страниц нечётная extract $ba first.bmp extract $bb second.bmp echo "Собираем странички $ba - $bb" else #Если ПАРА страниц чётная extract $bb first.bmp extract $ba second.bmp echo "Собираем странички $bb - $ba" fi
Для вытягивания страниц из исходного PDF-ника использовался GhostScript в виде команды:
gs -q -sDEVICE=bmpmono -r$DPI -dFirstPage=$1 -dLastPage=$1 -sOutputFile="$TMP_DIR/$2" -dNOPAUSE -dBATCH *pdf
Поскольку у меня исходный PDF-ник был без полей (для читалки так удобнее), я добавил ImageMagic-ом поля вокруг страницы:
convert "$TMP_DIR/$2" -define bordercolor=#ffffff -border 10% "$TMP_DIR/$2"
Мам скрипт
#!/bin/bash letsgo(){ echo "Продолжим? (Yes/[No])" read CONTINUE if [ -n "$CONTINUE" ] && [[ "$CONTINUE" == y* ]] || [[ "$CONTINUE" == Y* ]] #Строка не пустая и начинается с "y" или "Y" then echo "Ну что-ж, продолжаем..." else rm -R $TMP_DIR exit fi } extract(){ #FirstPage и LastPage=$1, OutputFile=$2 - БЕЗ ПРЕФИКСА! gs -q -sDEVICE=bmpmono -r$DPI -dFirstPage=$1 -dLastPage=$1 -sOutputFile="$TMP_DIR/$2" -dNOPAUSE -dBATCH *pdf convert "$TMP_DIR/$2" -define bordercolor=#ffffff -border 10% "$TMP_DIR/$2" #Добавляем рамку белого цвета } assembly(){ sub_a(){ for ((b=0; b<$1/2; b++)) do let "ba=$3+$b" #номер первой страницы на листе let "bb=$4-$b" #номер второй страницы на листе if [ "`expr $b % 2`" -gt "0" ] then #Если ПАРА страниц нечётная extract $ba first.bmp extract $bb second.bmp echo "Собираем странички $ba - $bb" else #Если ПАРА страниц чётная extract $bb first.bmp extract $ba second.bmp echo "Собираем странички $bb - $ba" fi convert +append $TMP_DIR/first.bmp $TMP_DIR/second.bmp "$TMP_DIR/$ba-$bb".pbm if [ "$b" -eq "0" ] then cjb2 -lossy "$TMP_DIR/$ba-$bb".pbm "$2".djvu else cjb2 -lossy "$TMP_DIR/$ba-$bb".pbm "$TMP_DIR/$ba-$bb".djvu djvm -i "$2".djvu "$TMP_DIR/$ba-$bb".djvu fi rm "$TMP_DIR/$ba-$bb".* done } if [ "$1" -gt "`expr $FILE_COUNT / $PAGES_IN_W_BOOK`" ] then #сборка последней тетради for ((a=0; a<1; a++)) do let "aa=$1" #номер тетради let "ab=$FILE_COUNT/$PAGES_IN_W_BOOK*$PAGES_IN_W_BOOK+1" #номер первой страницы в тетради let "ac=$FILE_COUNT" #номер последней страницы в тетради echo "Собираем тетрадь $aa состоящую из страниц $ab...$ac" sub_a $2 $aa $ab $ac done else # нормальное выполнение for ((a=0; a<$1; a++)) do let "aa=$a+1" #номер итерации в текущем цикле он же - номер тетради let "ab=$a*$2+1" #номер первой страницы в тетради let "ac=$a*$2+$2" #номер последней страницы в тетради echo "Собираем тетрадь $aa состоящую из страниц $ab...$ac" sub_a $2 $aa $ab $ac done fi } mkdir /tmp/brochure_converter #Создаём временный каталог TMP_DIR="/tmp/brochure_converter" #Назначаем переменную отражающую путь во временный каталог gs -q -sDEVICE=bmpmono -r2x2 -sOutputFile=$TMP_DIR/%d.bmp -dNOPAUSE -dBATCH *pdf #Извлекаем страницы из PDF в малом разрешении FILE_COUNT=`ls -l $TMP_DIR/*bmp | grep ^- | wc -l` #Подсчитываем количество страниц в документе посредством подсчёта количества файлов в каталоге echo "Укажите количество страниц в одной тетради кратное 4, например "8, 12, 16" и т.д." read PAGES_IN_W_BOOK #Считываем переменную количества страниц в тетради let "W_BOOK=$FILE_COUNT/$PAGES_IN_W_BOOK" #Вычисляем количество страниц в одной тетради echo "Будет сформировано $W_BOOK полных тетрадей по $PAGES_IN_W_BOOK страниц в каждой" let "TAIL_PAGES = $FILE_COUNT%$PAGES_IN_W_BOOK" #Вычисляем количество страниц в последней тетради echo "Остаётся неполная тетрадь на $TAIL_PAGES страниц" echo "Укажите требуемое разрешение изображений (DPI), например 72" read DPI #Назначаем переменную разрешения изображений будущего документа letsgo assembly $W_BOOK $PAGES_IN_W_BOOK #Передаём в процедуру позиционные параметры количества тетрадей и количества страниц echo "Выполнена сборка страниц основного набора, теперь можно собрать дополнительную тетрадь." letsgo let "LAST_W_BOOK=$W_BOOK+1" #Создаём переменную указывающую номер последней тетради if [ "`expr $TAIL_PAGES % 4`" -eq "0" ] #Если количество страниц в последней тетради then echo "Всё нормально, продолжаем создание последней тетради" assembly $LAST_W_BOOK $TAIL_PAGES else echo "В тетради недостаёт `expr 4 - $TAIL_PAGES % 4` страниц(ы)" echo "Следует добавить их. Вы можете их добавить вручную или позволить это сделать программе." letsgo #добавляем необходимое количество пустых файлов после чего приступаем к сборке fi rm -R $TMP_DIR
Проблемы
Мне крайне не нравится вот это решение:
gs -q -sDEVICE=bmpmono -r2x2 -sOutputFile=$TMP_DIR/%d.bmp -dNOPAUSE -dBATCH *pdf #Извлекаем страницы из PDF в малом разрешении FILE_COUNT=`ls -l $TMP_DIR/*bmp | grep ^- | wc -l` #Подсчитываем количество страниц в документе посредством подсчёта количества файлов в каталоге
Поэтому буду благодарен за подсказку как узнать количество страниц в PDF-нике не распаковывая его.
Заключение
Скриптик сырой. Не доделана обработка PDF-ника, содержащего количество страниц не кратное 4, публиковаться изначально здесь не планировал, ибо чукча — читатель.
Первый опыт, просьба сильно не пинать.
За идеи и поправки заранее благодарен.
Автор: lexx_z