четверг, 3 ноября 2016 г.

Linux: Как пережать PDF

Предположим, у нас есть некий pdf-документ, который надо разослать по электронной почте N адресатам. Казалось бы, не проблема: создавай N писем с вложенным документом и отправляй, благо, слепить на коленке софт под это дело - задача нехитрая.

Основная проблема - размер этого самого pdf-документа. При массовой рассылке объем переданной через почтовый сервер информации возрастёт в N раз, поэтому возникает логичное желание ужать пересылаемый документ как только можно. Сам документ получен со сканера, то есть фактически является увесистым набором изображений. С другой стороны, к счастью, тут качество не сильно важно, достаточно, чтобы текст читался, да подписи с печатями были различимы. Короче, задача сформулировалась так: получить из многостраничного сканированного документа черно-белый факс убогого качества, но читаемый, в формате pdf.

Никуда не деться, взял в качестве образца пятистраничный файл input.pdf размером 923801 байт и принялся экспериментировать.

Должен сказать, что самый правильный путь решения проблемы: воспользоваться Adobe Acrobat-ом. Эта чудесная софтина содержит команду "Optimize scanned PDF", которая при определенных настройках каким-то волшебным образом умудряется превращать исходный файл в жалкие 97416 байтов! К сожалению, в данный момент лицензионного Adobe Acrobat-а под рукой нет, поэтому приходится выкручиваться тем, что есть.

Первый вариант, который советуют знающие люди - использовать ghostscript. Соответствующая команда выглядит так:
gs \
    -sDEVICE=pdfwrite \
    -dCompatibilityLevel=1.4 \
    -dPDFSETTINGS=/screen \
    -dNOPAUSE \
    -dQUIET \
    -dBATCH \
    -sOutputFile=output.pdf 
    input.pdf
Результат получается вполне читаемым, но объем не сильно уменьшился и составил 548870 байтов.

Второй найденный на просторах инета вариант реализует идею уменьшить количество цветов до минимума:
#!/bin/sh

inFile=input.pdf
outFile=output.pdf

pdfimages "$inFile" scan1
for a in scan1*.p*m; do
   convert -depth 2 -colorspace gray $a ${a%.*}.tiff
done

tiffcp scan1*.tiff "scan1-.tiff"
tiff2pdf "scan1-.tiff" -o "$outFile" -p A4 -F -z

rm scan1*.*
Как видим, здесь используется несколько утилит: ImageMagick с его хитрой командой convert, а также LibTIFF (утилиты tiffcp и tiff2pdf). Результат: 380120 байтов. Неплохо, но далеко от рекорда.

Далее возникла мысль вообще перекодировать pdf в монохромный режим. Сделать это просто, достаточно чуть-чуть модифицировать тело цикла в предыдущем варианте:
#!/bin/sh

inFile=input.pdf
outFile=output.pdf

pdfimages "$inFile" scan1
for a in scan1*.p*m; do
    convert -white-threshold 100% -monochrome   $a   ${a%.*}.tiff
done

tiffcp scan1*.tiff "scan1-.tiff"
tiff2pdf "scan1-.tiff" -o "${outFile%.*}.${outFile##*.}" -p A4 -F -z

rm scan1*.*
Результат всё ещё читаем и имеет размер 252072 байта.

Ещё один вариант, который стоило попытаться сделать - это уменьшить в два раза размеры отсканированных изображений перед тем, как переводить их в монохром. Идея показалась здравой, но, будучи применена "в лоб", дала совершенно нечитаемый результат.

Можно попробовать ещё один подход: попытаться векторизовать содержащиеся в исходном файле изображения. Оказывается, есть специальная утилита для этого дела: Potrace. Правда, если применить её так:
#!/bin/sh

inFile=input.pdf
outFile=output.pdf

pdfimages "$inFile" scan1
for a in scan1*.p*m; do
    mkbitmap -f 2 -s 1 -x -t 0.8  $a  -o ${a%.*}-step1.${a##*.}
done

potrace -b pdf -t 5 scan1-*-step1.p*m -o "$outFile"

rm scan1*.*
то результат хоть и выглядит забавно, но оказался совсем тяжелым, 1440526 байтов.

Однако нет худа без добра: в дистрибутиве Potrace обнаружилась замечательная утилита mkbitmap, которая позволяет подправить изображение при преобразовании в монохром. Если её полезные свойства скомбинировать с предыдущими вариантами, то получается такой скрипт:
#!/bin/sh

inFile=input.pdf
outFile=output.pdf

pdfimages "$inFile" scan1
for a in scan1*.p*m; do
   mkbitmap -f 2 -s 1 -x -t 0.8          $a                -o ${a%.*}-step1.pbm
   convert -depth 2 -colorspace gray     ${a%.*}-step1.pbm    ${a%.*}-step2.tiff
   convert -resize 50%                   ${a%.*}-step2.tiff   ${a%.*}-step3.tiff
done

tiffcp scan1*-step3.tiff "scan1-.tiff"
tiff2pdf "scan1-.tiff" -o "$outFile" -p A4 -F -z

rm scan1*.*
и это оказался лучший результат: 180664 байта при всё ещё различимом тексте.

Вывод: конечно, до рекорда Adobe Acrobat-а ещё очень далеко, но, как говорится, забесплатно и уксус сладкий. Буду пока пользоваться этим.

Комментариев нет:

Отправить комментарий