Еще один способ генерации PDF

Website development
Где это может пригодиться? При необходимости генерации готовых к печати файлов в web-приложении по уже имеющемуся произвольному жесткому шаблону: сертификаты, бейджи, пропуски и прочее.

Почему PDF? Формат PDF позволяет создавать документы с целым рядом неоспоримых преимуществ: открытость, кроссплатформеность, распространенность и, что очень важно, точностью и неизменностью передачи данных по цепочке создание, просмотр и печать.

В чем соль? В использовании SVG файлов как шаблонов с возможностью подстановки необходимых полей с последующим преобразованием в PDF.

Какие преимущества? Возможность создания и быстрого редактирования очень сложных шаблонов в привычных векторных редакторах, таких как Adobe Illustrator, Corel Draw или Inkscape. Простота программирования и использование только бесплатных программных средств. Еще одним важным преимуществом является возможность прозрачно использовать UTF-8 для вставляемых текстов.

Что для этого надо? Для использования данного метода нужен выделенный сервер с возможностью установки своих приложений (Inkscape и GhostScript) и выполнением system-команд. При этом всё будет работать как на Windows платформе, так и на Linux.

Думаю, краткий FAQ осветил основные вопросы по данному методу, потому сразу приступим к разбору его сути.

Как известно, формат векторной графики SVG фактически представляет собой XML-файл, поэтому уже созданный файл достаточно просто редактировать простейшими средствами программирования. В случае использования SVG файла как жесткого шаблона, процесс упрощается в разы, т.к. нам нет необходимости менять структуру документа, а нужно лишь произвести подстановку нужных текстовых значений или кодированных в base64 растровых изображений.

Создать первоначальный шаблон можно в любом векторном редакторе поддерживающем экспорт в svg: Adobe Illustrator, Corel Draw или в самом Inkscape’е. Использование последнего желательно, хотя бы на последней, доводочной стадии, так как, в конечном счете, именно ему и предстоит производить необходимое нам преобразование.

При использовании растра в шаблоне, можно использовать 2-а метода, хранить растр в отдельном внешнем файле или встроенным в сам SVG файл. При необходимости менять в шаблоне растровый рисунок в первом случае можно перед генерацией менять и файл. При хранении рисунка встроенным в файл, следует в свойстве URL объекта рисунка прописать строку:
Data:image/png;base64,{IMAGE}

где {IMAGE} — это поле для вставки шаблонизатором base64 кодированного изображения.
Data:image/png;base64,{IMAGE}
Для примера нарисуем простенький шаблон бейджа, думаю вы меня простите за кривость, я не художник, а для реального использования, вы можете заказать у вашего дизайнера векторный макет.
Шаблон бейджа
Я не стал использовать изменяемое растровое изображение, оставив это на домашнее задание, а ограничился лишь изменяемыми текстовыми полями.

Думаю, вы уже обратили внимание на то, что в местах предполагаемого текста вставлены тэги шаблонизатора (в данном примере использовался FastTemplate). Именно использование XML совместимых тегов дает возможность прописывать их в самом векторном редакторе не прибегая к дополнительному редактированию.

Мы имеем шаблон, и уже без проблем сможем вставить необходимые нам данные, но как собственно мы будем проводить преобразование? Для этого воспользуемся интерфейсом командной строки Inkscape:
#преобразование в PDF-файл
inkscape [source_svg_file] -A [dest_pdf_file]

Используя ключ «-A» мы сразу получим PDF файл, но, к сожалению, создаваемый напрямик PDF имеет очень большие размеры. Для решения этой проблемы можно пойти в обход. А именно, использовать экспорт SVG не на прямую в PDF, а по цепочке SVG->PS->PDF. Использовав для конечного формирования PDF файла утилиту ps2pdf из комплекта Ghost Script, мы можем уменьшить размеры финального файла в десятки раз.
#преобразование в PostScript-файл
inkscape [source_svg_file] -P [dest__ps_file]
#преобразование в PostScript-файла в PDF
ps2pdf [dest_ps_file] [dest_pdf_file]

Единственный минус в том, что в этом случае мы потеряем все эффекты прозрачности, так как формат PostScript его не поддерживает.

Для полной переносимости сгенерированных документов, можно добавить Inscape’у опцию «-T» преобразования всего текста в кривые. Этим самым мы сможем избавиться от проблем наличием шрифтов на клиентской машине, а также от проблем с кодировками.

Теперь мы имеем, всё необходимое: SVG шаблон и команды преобразований. Напишем php-скрипт, который бы выдавал pdf-файл сгенерированный из шаблона.

<?php
/* ****************************************************************************************
* Скрипт формирования pdf-файла пропуска с помощью последовательного преобразования
* шаблона в svg файл, после чего тот преобразуется в PostScript файл программой Inkscape,
* и последний преобразуется в pdf с помощью утилиты ps2pdf.
*
* Автор: Шебастюк В.В. a.k.a. JStingo
* **************************************************************************************** */

/* параметры скрипта */

//Путь к папке с временными файлами
//(если не указан, то файлы будут хранится в системной временной папке)
$tmp_dir='';

//генерируем пути к временным svg, ps и pdf файлам
$tmp_svg_file=tempnam($tmp_dir,"");
$tmp_ps_file=tempnam($tmp_dir,"");
$tmp_pdf_file=tempnam($tmp_dir,"");

/* Шаблонизатор FastTemplate */
include(«include/cls_fast_template.php»);
$tpl = new FastTemplate(«templates»);

try{

/* Блок с получаемыми для шаблонизации данными */
/* ........................... */
$user_name='JStingo';
$register_date='28/09/2007';
/* ........................... */
/* формируем имя результрующего файла в виде User_name.pdf */

$pdf_file_name=$user_name.'.pdf';

/* обработка шаблона и получение результрующего файла */

$tpl->define( array('svg' => «template.svg»));
$tpl->assign(array( 'USER_NAME' => $user_name,
'R_DATE' => $register_date
));
$tpl->parse('SVG', 'svg');

//сохраням полученный svg файл
$tpl->FastWrite('SVG',$tmp_svg_file);

//производим конвертацию svg-файла средствами inkscape'а в ps-файл
//Ключи
// -T — служит для преобразования текста в кривые (для нормальной поддержки шрифтов)
// -P — указывает на необходимость преобразования в PostScript-файл
system(«inkscape -T $tmp_svg_file -P $tmp_ps_file»,$success);

//в случае неудачного выполнения преобразования формируем исключение
if($success!=0)
throw new Exception(«Ошибка формирования ps-файла.»);

//преобразуем ps-файл в pdf с помощью утилиты ps2pdf

//Ключи
// -dUseFlateCompression=true — устанавливает использование компрессии
// -dPDFSETTINGS=/printer — устанавливает оптимизацию для печати
system(«ps2pdf -dUseFlateCompression=true -dPDFSETTINGS=/printer $tmp_ps_file $tmp_pdf_file»,$success);

//в случае неудачного выполнения преобразования формируем исключение
if($success!=0)
throw new Exception(«Ошибка формирования pdf-файла.»);

//заголовок о том, что будем оправлять pdf-файл
header('Content-type: application/pdf');

// Называться будет как $pdf_file_name
header('Content-Disposition: attachment; filename="'.$pdf_file_name.'"');

// передаем сгенерированный файл
readfile($tmp_pdf_file);

//удаляем временные файлы
@unlink($tmp_svg);
@
unlink($tmp_ps_file);
@
unlink($tmp_pdf_file);

}
catch(Exception $e){
/* Если где-то произошла ошибка, то сообщаем об этом */
$tpl->define( array('error' => «error.tpl»));
$tpl->assign('ERROR',$e->getMessage());

$tpl->parse('ERROR', 'error');
$tpl->FastPrint('ERROR');
}
?>

Думаю, всем не составит особого труда переписать скрипт на другом языке программирования.
Пример сгенерированного скриптом файла.

Шаблон и рабочий скрипт (при условии установленных Inkscape и GhostScript).
Tags:pdfsvgpsinkscapephp
Hubs: Website development
+28
17.6k 119
Comments 25

Popular right now

Комплексное обучение PHP
April 19, 202120,000 ₽Loftschool
Python для анализа данных
March 3, 202124,900 ₽SkillFactory
Профессия Product Manager
March 3, 2021108,500 ₽Нетология
Профессия Data Scientist
March 3, 2021162,000 ₽SkillFactory
Специализация Data Science
March 3, 2021114,000 ₽SkillFactory