Этот сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Текст в PDF

Попалась задача — преобразовать огромный (полтора миллиона строк) тестовый файл в кодировке UTF-8 в PDF. Не ожидал с ней каких-то сложностей, но оказалось, что это не так-то просто.

Проблемы две — объём текста и кодировка. Графические утилиты на таком объёме умирают, а с кодировкой UTF, как оказалось, работают далеко не все утилиты командной строки.

Перебрал несколько, с задачей справилась только утилита paps. Хочу себе это записать, чтобы не пришлось заниматься перебором, если в будущем столкнусь с такой же задачей.

Ещё в моей задаче первый лист должен быть пустым и на каждом листе должен быть номер страницы. В результате строка запуска выглядит так:

paps --footer --footer-center={page_idx} <(printf \\f;cat listing.txt) -o listing.pdf

Небольшое примечание: при помощи printf я вставляю текстовый символ разрыва страницы (\f), чтобы первая страница оказалась пустой.

3 комментария
Andrey Rakhubovsky 6 дн

В принципе, pandoc (https://pandoc.org/) справляется, но заставить его сделать первый лист пустым — очень нетривиальная задача, проще приклеить пустую страницу к готовому файлу.

Евгений Степанищев 6 дн

Я пробовал, у меня не справился. Уже не помню в чём там дело было.

…проще приклеить пустую страницу к готовому файлу

А пронумеровать потом, после этого?

Andrey Rakhubovsky 6 дн

А первая (пустая) страница должна тоже быть пронумерована? Тогда надо как-то это объяснить пандоку. Я так понимаю, что он через латех все компилирует, а в латехе все оптимизировано, чтобы подавлять ненужные пустые места в документе, особенно на первой странице. Можно это обойти, например, скомандовав ему разместить на первой странице прозрачную картинку или другим подобным способом, надо немножко над этим подумать.

Если первая страница может быть без номера, а нумерация остальных может начинаться с единицы, то как-то так будет работать (не знаю, как код размечать):

tr -cd 'a-zA-Z ' < /dev/urandom | head -c8000000 | fold -w80 > /tmp/2.txt | ( echo "Пандок" && cat ) | sed G | pandoc -o /tmp/1.pdf --pdf-engine=xelatex --variable mainfont="Unifont" --variable "geometry=margin=1in"

Тут важно прописать, что для сборки PDF используется xelatex, потому что используемый по умолчанию pdflatex не работает с юникодом, и указать шрифт, который содержит нужные символы — здесь Unifont, потому что он покрывает очень значительную часть юникода. Ну и ’sed G’ нужно, чтобы разделять строки пустыми строками, потому что иначе переносы строк будут проигнорированы.

В этом примере 100 тысяч строк, но я не думаю, что от масштабирования что-то сломается.

Евгений Степанищев 6 дн

(не знаю, как код размечать)

Увы, никак :-(

Резюме: через paps проще.

Andrey Rakhubovsky 6 дн

Paps еще и быстрее раза в три.