Начну с того, что есть несколько различных подходов к решению данной задачи:
- Создание PDF "с нуля" (PDF::API2, PDF::Haru, PDF::CreateSimple)
- Модификация уже существующего PDF-бланка (PDF::Reuse, PDF::API2, PDF::Haru, PDF::CreateSimple)
- Создание PDF из XML-шаблона при помощи XSLT-преобразования (XML::ApacheFOP)
- Конвертация LaTeX или HTML файла в PDF внешними утилитами (исходые файлы при этом можно генерировать по шаблону, к примеру, Template::Toolkit)
У каждого подхода есть свои плюсы и минусы, так что выбор зависит от конкретной ситуации. В этой же статье четь пойдёт о первом подходе, а точнее о создании PDF-файлов при помощи модуля PDF::API2.
Краткий обзор PDF::API2
Модуль PDF::API2 - ветеран среди PDF-модулей на CPAN. Проект насчитывает уже несколько лет и обладает внушительным функционалом. Стоит отметить, однако, что интерфейс PDF::API2 довольно запутан и не всегда очевиден, кроме того, работать придется с довольно низкоуровневыми элементами (графические примитивы, строки текста и т.д.). Последний недостаток отчасти компенсируют модули-обёртки с более удобным интерфейсом: PDF::API2::Simple, PDF::Table.
В целом, работа с PDF::API2 напоминает рисование: получить графический контекст, задать необходимые атрибуты (цвет, фон, стиль начертания), вызвать соответствующий метод-примитив (текст, прямоугольник, дуга и т.д.).
Ниже приводится небольшой скрипт для создания минимального PDF-файла. Следующим шагом рекомендую ознакомиться с отличным tutorial-ом по данной теме: Using PDF::API2. Ну а осилив и его, можно уже открывать документацию по PDF::API2. Итак, пример:
Пример
#!/usr/bin/perl
#===============================================================================
# REVISION: $Id$
# DESCRIPTION: Минимальный пример использования PDF::API2
# AUTHOR: Alexander Simakov, <xdr (dot) box (at) Gmail>
# http://alexander-simakov.blogspot.com/
# LICENSE: Public domain
#===============================================================================
use strict;
use warnings;
our $VERSION = qw($Revision$) [1];
use Readonly;
use PDF::API2;
# Размер бумаги A4
Readonly my $PAGE_WIDTH => 210;
Readonly my $PAGE_HEIGHT => 297;
# Внутренняя единица измерения PDF::API2 - пункты
# см. http://ru.wikipedia.org/wiki/Типографский_пункт
Readonly my $ONE_MILLIMETER_IN_POINTS => 72 / 25.4;
# Перевод миллиметров в типографские пункты
sub _mm_to_pt {
my $mm = shift;
return $mm * $ONE_MILLIMETER_IN_POINTS;
}
sub main {
# Создаём PDF-объект
my $pdf = PDF::API2->new( -file => 'example.pdf' );
# Создаём новую станицу размера A4
my $page = $pdf->page();
$page->mediabox( _mm_to_pt($PAGE_WIDTH), _mm_to_pt($PAGE_HEIGHT) );
# Встраиваем в PDF-файл шрифты
my %fonts = (
Helvetica => {
Bold => $pdf->corefont('Helvetica-Bold'),
Roman => $pdf->corefont('Helvetica'),
Italic => $pdf->corefont('Helvetica-Oblique'),
},
);
# Напишем строку текста
my $text_ctx = $page->text();
$text_ctx->font( $fonts{'Helvetica'}{'Bold'}, 12 );
$text_ctx->fillcolor('red');
# В PDF::API2 - начало координат в левом нижнем углу
$text_ctx->translate(
_mm_to_pt( $PAGE_WIDTH / 2 ),
_mm_to_pt( $PAGE_HEIGHT / 2 )
);
# Выводим строку с выравниванием по центру
$text_ctx->text_center('Hello PDF::API2');
$pdf->save();
return;
}
main();
А вот результат: example.pdf
Скачать скрипт: create_example_pdf.tar.gz
Заключение
Модуль PDF::API2 позволяет достаточно тонко и точно контроллировать процесс создания PDF-файла, но за всё приходится платить. В данном случае плата - это довольно большое количество усилий необходимых для выполнения относительно простых операций.
Ссылки

Еще существует вариант использовать fop. К перлу это иммет мало отношения, но штука удобная (но не очень быстрая). На xml c данными накладывается xslt со специальным шаблоном для отображения, результат этого действия засовывается в fop и на выходе получается pdf.
ОтветитьУдалитьВ перле есть интерфейс к fop-у --- модуль XML::ApacheFOP, но к сожалению этот модуль не обновлялся с 2005 года. К тому же для его запуска требуется Java-сервер, что добавит хлопот, тем то не каждый день сталкивается с Java.
ОтветитьУдалитьЯ смотрел этот модуль, но решил его не использовать (уже причины этого не помню). Для работы с fop выполнятся просто одна команда через system и все.
ОтветитьУдалитьJava — да плохо, зато у fop огромный плюс в том, что он идеологически правильный: данные отдельно, шаблон отдельно. И на мой вкус интрфейс fop лучше чем у перловых модулей создания xml.
Попробую fop при случае. Вариант с шаблоном (будь то XML или Template::Toolkit) действительно более гибкий и удобный.
ОтветитьУдалить