в Bash и Linux

Преобразование PDF в PNG

На этой неделе передо мной стала новая задача — из PDF сделать картинку вменяемого формата — JPG, PNG или GIF.

Задача на первый взгляд достаточно тривиальная и часто встаёт в самых разнообразных проектах. Обычно конвертируют только первую страницу — для создание превью PDF на php. Моя задача несколько отличалась — дать возможность клиентам скачивать платёжные документы не только в общепринятом PDF, но и формате обычной картинки.
Первое же решение, которое я нашёл погуглив, оказалось с серьёзным изъяном. Но давайте по-порядку.

Imagick

При слове «конвертация» на ум сразу приходит пакет ImageMagick и его реализация для php — Imagick. Точнее это обёртка над консольной утилитой convert. Imagick документирован средне, но при желании разобраться достаточно не сложно.
Вот и решение, очень простое и понятное:

  1. <?php
  2. $obPdf = new Imagick( ‘act.pdf[0]’ ); #Открываем наш PDF и указываем обработчику на первую страницу
  3. $obPdf->setImageColorspace(255); #устанавливаем цветовую палитру
  4. $obPdf->setCompression(Imagick::COMPRESSION_JPEG); #Устанавливаем компрессор
  5. $obPdf->setCompressionQuality(60); #И уровень сжатия
  6. $obPdf->setImageFormat(‘jpeg’); #С форматом не заморачиваемся — пусть будет JPEG.
  7. #При необходимости сделать превью ресайзим изображение
  8. $obPdf->resizeImage(250, 250, imagick::FILTER_LANCZOS, 1);
  9. #Ну и конечно же пишем в jpg-файл.
  10. $obPdf->writeImage(‘act_preview.jpg’);
  11. $obPdf->clear();
  12. $obPdf->destroy();
  13. ?>

Решение действительно хорошее и в целом с задачей справляется. Но в моём случаем возникли проблемы со шрифтами. Хотя в pdf был зашит Times New Roman, стандартный даже для *nix-осей шрифт, картинка получилась корявая, шрифт расползся из-за чрезмерного кернинга — расстояния между буквами были в хороших 5 пикселей.
Я потратил на копание в настройках иксов, convert, imagick, ghostscript и прочих частей преобразовательного хозяйства почти целый день, но кроме локализации проблемы сделать ничего не удалось. Устройство ImageMagick’a — тема отдельной статьи, которая появится в ближайшее время. Пока же вывод печален — пришлось переключится на поиски другого решения.

XPDF

После непродолжительных поисков была найдена замена — пакет xpdf, который тут же завёлся прямо из репозитария debian:

  1. sudo apt-get install xpdf

Пакет содержит целый ряд утилит и прямо после установки я воспользовался простой командой:

  1. pdftoppm act.pdf -png /path/to/image

И на выходе получил чудесный, прекрасно конвертированный файл формата pdf и разрешения в полторы сотни dpi. Правда c названием image-1.png — но это не беда. Утилита прописывает номер страницы файла в постфиксе имени.
Собственно pdftoppm изначально преобразовывала в формат ppm (Portable Bitmap — немного пожатый аналог bmp), но мне не хотелось возится с промежуточным файлом и использованием ppmtojpeg. Выручил ключ «-png». По мануалам в сети он отсутствует, но мой баш подсказал, что ключик есть.

Дальнейшее было делом техники.

  1. <?php
  2. $realFileName = ‘/uploads/act.pdf’;
  3. $fileName = ‘/path/to/preview/act’;
  4. exec(‘pdftoppm ‘.$realFileName.‘ -png ‘.$fileName);#вызываем консольную утилиту
  5. $fileName .= ‘-1.png’;#Добавляем постфикс к имени-пути файла
  6. LL(‘File’)->createFileFromReal(‘file1’, $fileName);
  7. unlink($fileName);?>
  • Максим

    $realFileName = ‘/srv/www/htdocs/1.pdf’;
    $fileName = ‘/srv/www/htdocs/files/pdf’;

    exec(‘pdftoppm ‘.$realFileName.’ -r 300 ‘.$fileName);

    exec(‘for file in /srv/www/htdocs/files/*.ppm; do ppmtojpeg $file > ${file/.ppm/.jpg}; rm $file; done’);