Showing posts with label Ghostscript. Show all posts
Showing posts with label Ghostscript. Show all posts

Wednesday, July 08, 2009

Повышение качества изображения при переводе из PDF в JPEG

Если использовать пример из предыдущего поста для перевода PDF в JPEG, можно заметить потерю качества изображения, особенно если оно сильно уменьшается в размерах, например, при создании thumbnails:





Слева результат работы Ghostscript (скачать файл Gordon_Moore_1965_Article.pdf, 820 КБ):

c:\Temp>"c:\Program Files\gs\gs8.64\bin\gswin32c.exe" -dSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -r30 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dMaxStripSize=8192 -sOutputFile=page-%d.jpg Gordon_Moore_1965_Article.pdf

Справа - ImageMagick, набора программ для обработки изображений:

c:\Temp>"c:\Program Files\ImageMagick-6.5.4-Q16\convert.exe" -resize 255x330 Gordon_Moore_1965_Article.pdf output.jpg

Можно заметить, что ImageMagick справился с задачей лучше (на картинке сверху контуры изображения остались более четкими, а сетка на графике точно повторяет исходное расположение как в PDF).

Согласно документации, для перевода PDF файлов в графический формат, ImageMagick использует Ghostscript. Чтобы понять откуда разница в качестве посмотрим, с какими параметрами ImageMagick вызывает Ghostscript (я на время переименовал папку "c:\Program Files\gs", чтобы ImageMagick не смог найти Ghostscript):

c:\Temp>"c:\Program Files\ImageMagick-6.5.4-Q16\convert.exe" -resize 255x330 Gordon_Moore_1965_Article.pdf output.jpg
convert.exe: `%s': %s "C:/Program Files/gs/gs8.64/bin/gswin32c.exe" -q -dQUIET -dPARANOIDSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dEPSCrop -dAlignToPixels=0 -dGridFitTT=0 "-sDEVICE=bmpsep8" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r72x72" -dUseCIEColor "-sOutputFile=C:/Users/DMITRY~1/AppData/Local/Temp/magick-zgPdpP6n" "-fC:/Users/DMITRY~1/AppData/Local/Temp/magick-xyf_86Fy" "-fC:/Users/DMITRY~1/AppData/Local/Temp/magick-ETtA_r9y" @ utility.c/SystemCommand/1880.
convert.exe: Postscript delegate failed `Gordon_Moore_1965_Article.pdf': No such file or directory @ pdf.c/ReadPDFImage/611.
convert.exe: missing an image filename `output.jpg' @ convert.c/ConvertImageCommand/2772.


Помимо прочих параметров, основным отличием является использование специфического устройства вывода (-sDEVICE=bmpsep8). На основании входного файла ImageMagick определяет промежуточный формат, в который он должен перевести содержимое PDF без потери качества. Это может быть RAW-формат (например, pnmraw) или, как в примере, bmpsep8. Дальнейшие трансформации (например, изменение размера) ImageMagick производит на этом временном файле.

Известно, что RAW/BMP файлы имеют большой размер (пропорционально размеру канвы изображения), и даже если на выходе мы хотим получить файл размером 255x300, как в примере, промежуточный файл может быть гигантских размеров. Поэтому нужно быть осторожным при использовании такого метода конвертации, особенно если вы заведомо не знаете о содержимом ваших PDF-файлов.


Так, например, для PDF в 544 КБ (скачать можно здесь), размер промежуточного файла ImageMagick составляет 1,6 ГБ (!). На выходе получается JPEG на 8 КБ, при этом процедура конвертации занимает около 5 минут. Та же самая процедура с использованием Ghostscript + JPEG device занимает меньше секунды при размере выходного файла 4 КБ, но подбирать параметры масштабирования в данном случае приходится вручную. Результат представлен ниже (слева Ghostscript, справа - ImageMagick), о качестве судите сами.


GhostscriptImageMagick



При тестировании использовались Ghostscript 8.64 и ImageMagick 6.5.4-2-Q16.

P.S.
Список поддерживаемых Ghostscript devices можно найти здесь: http://www.gnu.org/software/ghostscript/devices.html.

В одном из следующих постов я расскажу как можно организовать пакетную печать PDF-документов в Windows, используя Ghostscript и устройство mswinpr2.

Wednesday, April 29, 2009

Использование Ghostscript для перевода PDF в JPEG

В одном из последних проектов я занимался пакетной обработкой pdf-документов: слияние (merge) документов и распознание 1D штрих-кодов (barcode recognition).

Хочу поделиться интересными, на мой взгляд, особенностями и ссылками на Open Source-проекты.

С первой задачей (merge документов) отлично справился PDFsharp - Open Source-проект со свободной лицензией и с достаточно простым и удобным API (.Net).

Со штрих-кодами оказалось немного сложнее. Дело в том, что основной формат документов для "читалок" - файлы изображений (jpeg, png, tiff и т.д.), а перевести PDF в картинку оказалось не так просто...

Мы решили эту задачу с помощью Ghostscript - Open Source (GPL License) интерпретатор языка PostScript и пакет для работы с PDF.

Вообще говоря, перевести PDF в картинку, используя Ghostscript, можно одной командой, примерно так:


c:\Temp>c:\dev\bin\gs\gs8.64\bin\gswin32c.exe -q -dSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -r150 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dMaxStripSize=8192 -sOutputFile=page-%d.jpg mydocument.pdf


На выходе должно быть несколько файлов (по одному на страницу): в данном случае page-1.jpg, page-2.jpg и т.д.

Проблемы начинаются, если PDF-документ содержит экзотические шрифты (например, IDAutomationHC39M.ttf - шрифт штрих-кода Code39), или если документ был создан при помощи MS Reporting Services или другой программы, которая по тем или иным причинам не включает используемые шрифты в выходной PDF-файл (PDF fonts embedding).

Наш PDF был именно такой:



В результате во время рендеринга у меня возникла такая ошибка:


Error: /undefined in findresource
Operand stack:
--nostringval-- --dict:7/16(L)-- F14 10.0 --dict:5/5(L)-- --dict:5/5(L)-- TimesNewRoman,Bold --dict:11/12(ro)(G)-- --nostringval-- CIDFontObject --dict:6/6(L)-- --dict:6/6(L)-- Adobe-Identity
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push 1862 1 3 %oparray_pop 1861 1 3 %oparray_pop 1845 1 3 %oparray_pop --nostringval-- --nostringval-- 3 1 2 --nostringval-- %for_pos_int_continue --nostringval-- --nostringval-- --nostringval-- --nostringval-- %array_continue --nostringval-- false 1 %stopped_push --nostringval-- %loop_continue --nostringval-- --nostringval-- --nostringval-- --nostringval-- --nostringval-- --nostringval-- %array_continue --nostringval-- --nostringval-- --nostringval-- --nostringval-- --nostringval-- %loop_continue --nostringval-- --nostringval-- --nostringval-- %loop_continue
Dictionary stack:
--dict:1156/1684(ro)(G)-- --dict:1/20(G)-- --dict:74/200(L)-- --dict:74/200(L)-- --dict:106/127(ro)(G)-- --dict:278/300(ro)(G)-- --dict:22/25(L)-- --dict:4/6(L)-- --dict:21/40(L)-- --dict:10/13(L)--
Current allocation mode is local
Last OS error: No such file or directory
GPL Ghostscript 8.64: Unrecoverable error, exit code 1


Ошибка связана с тем, что у меня на компьютере нет шрифта TimesNewRoman,Bold.

В Интернете все упоминания о подобных ошибках связаны с использованием японского или корейского шрифтов, но у меня в документе находится обычный английский текст.

Обратите также внимание на кодировку шрифта: Identity-H. Из того, что мне удалось выяснить, эта кодировка говорит о том, что используемый шрифт, вообще говоря, не существует, и в документе используются только коды символов. Для отображения символов, соответствующих этим кодам Ghostscript'у нужно "подсунуть" шрифт с аналогичной таблицей символов. Как это сделать описано в документации Ghostscript (см. CID Font Substitution).

В кратце, в файл c:\dev\bin\gs\gs.8.64\lib\cidfmap (этот файл не будет создан, если при установке вы не отметили галочку "Use Windows TrueType fonts for Chinese, Japanese and Korean"; в этом случае создайте его сами) нужно добавить инструкцию, которая будет указывать, какой шрифт использовать на самом деле вместо того, который указан в PDF.

У меня заняло некоторое время, чтобы подобрать параметры для этой инструкции. Дело в том, что нельзя заменить шрифт на любой другой (например, я не могу заменить мой английский шрифт на японский или корейский). Кроме как в исходниках я нигде больше не смог найти, что нужно подставить на место /CSI Ordering. В итоге получилась такая строчка:


/TimesNewRoman,Bold << /FileType /TrueType /Path (timesbd.ttf) /SubfontID 0 /CSI [(Unicode) 0] >> ;


Файл timesbd.ttf я взял из папки C:\Windows\fonts. Есть некоторые особенности использования абсолютных и относительных путей файла с использованием опции -dSAFER. Если указана эта опция, то путь к имени файла шрифта должен быть относительным. Поэтому я скопировал его в папку c:\dev\bin\gs\fonts (в моем случае именно она используется для поиска шрифтов по умолчанию).

Чтобы посмотреть детальные логи работы Ghostscript, нужно убрать опцию -q, и вот что мы увидим:


GPL Ghostscript 8.64 (2009-02-03)
Copyright (C) 2009 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 2.
Page 1
Substituting font Helvetica for IDAutomationHC39M.
Loading NimbusSanL-Regu font from %rom%Resource/Font/NimbusSanL-Regu... 2875432 1123207 25112624 23807796 3 done.
Loading NimbusRomNo9L-Regu font from %rom%Resource/Font/NimbusRomNo9L-Regu... 2912216 1253685 25112624 23819376 3 done.
Loading NimbusRomNo9L-Medi font from %rom%Resource/Font/NimbusRomNo9L-Medi... 3069576 1402046 25132720 23832802 3 done.
Page 2
Substituting font Helvetica for IDAutomationHC39M.
Loading NimbusSanL-Bold font from %rom%Resource/Font/NimbusSanL-Bold... 3166648 1539642 25152816 23854836 3 done.
Loading a TT font from C:\dev\bin\gs\fonts/timesbd.ttf to emulate a CID font TimesNewRoman,Bold ... Done.


Ошибка пропала, но при рендеринге штрих-кода вместо "правильного" шрифта использовался Helvetica. Это связано с тем, что Ghostscript не может использовать системные шрифты по-умолчанию. Эту проблему я решил копированием файлов шрифтов (IDAutomationHC39M.ttf и IDAutomationHC39M_0.ttf) в папку C:\dev\bin\gs\fonts и указанием ключика -sFONTPATH="C:\dev\bin\gs\fonts".

В результате получаем:


c:\Temp>c:\dev\bin\gs\gs8.64\bin\gswin32c.exe -sFONTPATH="C:\dev\bin\gs\fonts" -dSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -r150 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dMaxStripSize=8192 -sOutputFile=page-%d.jpg mydocument.pdf

GPL Ghostscript 8.64 (2009-02-03)
Copyright (C) 2009 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 2.
Page 1
Scanning c:\dev\bin\gs\fonts for fonts... 3 files, 3 scanned, 2 new fonts.
Loading IDAutomationHC39M font from c:\dev\bin\gs\fonts/IDAutomationHC39M.ttf... 2868992 1068452 25189416 23882410 3 done.

Loading NimbusRomNo9L-Regu font from %rom%Resource/Font/NimbusRomNo9L-Regu... 2885680 1201118 25209512 23896006 3 done.
Loading NimbusRomNo9L-Medi font from %rom%Resource/Font/NimbusRomNo9L-Medi... 3022944 1346357 25209512 23905928 3 done.
Loading NimbusSanL-Regu font from %rom%Resource/Font/NimbusSanL-Regu... 3120016 1438677 25531048 24170429 3 done.
Page 2
Loading IDAutomationHC39M font from c:\dev\bin\gs\fonts/IDAutomationHC39M.ttf... 3120016 1443415 25189416 23883485 3 done.
Loading NimbusSanL-Bold font from %rom%Resource/Font/NimbusSanL-Bold... 3217088 1539692 25229608 23926657 3 done.
Loading a TT font from C:\dev\bin\gs\fonts/timesbd.ttf to emulate a CID font TimesNewRoman,Bold ... Done.


Хочется отметить еще одну полезную опцию Ghostscript: -r150. Если этот параметр не указывать, то рендеринг будет происходить в мастшабе по умолчанию, в результате чего из-за маленьких размеров не распознавался штрих-код. Увеличение размера до 150 пикселей на дюйм (-r150) это исправило.

Аналогично можно также уменьшать размер картинки, например, чтобы сделать thumbnails (см. заметки по качеству перевода PDF в JPEG).