Предположим, у нас есть некий 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-а ещё очень далеко, но, как говорится, забесплатно и уксус сладкий. Буду пока пользоваться этим.