Pull to refresh

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

Reading time 8 min
Views 19K
Где это может пригодиться? При необходимости генерации готовых к печати файлов в 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:
Hubs:
+28
Comments 25
Comments Comments 25

Articles