Php генерация pdf из html. Сравнение способов генерации pdf из html. Отправляем документ PDF браузеру

Генерация pdf-документов является повседневной задачей в веб-разработке. В перечень таких документов входят счета, накладные, полисы и прочие. Существует множество готовых библиотек для решения этой задачи, в том числе и для php. Например, mpdf ,tcpdf , и многие другие. Файл можно собрать с помощью api этих библиотек, но это довольно долгое занятие. А времени на реализацию задачи много не бывает, не так ли? Поэтому чаще всего pdf-файл создается из html-представления, что довольно удобно. Но, к сожалению, не все так просто. У такого подхода есть множество подводных камней, способных вывести из себя кого угодно.

Например:

  • Стили нельзя подключить отдельно, следовательно они должны быть включены в html-документ отдельным блоком, либо инлайново для каждого элемента. В этом нет ничего страшного, небольшое неудобство.
  • К сожалению, в таких библиотеках некоторые стили могут работать не так как этого от них ожидаешь, либо не работать в принципе. Это самый главный недостаток.
  • Из предыдущего пункта следует, что создать документ максимально соответствующий требованиям очень трудоемко, а порой просто невозможно.
  • А в случае разработки под Битрикс есть еще одна проблемка. Все знают, что для работы платформы требуется в php.ini установить параметр mbstring.func_overload в значение 2. А для создания pdf-файла, содержащего кириллицу потребуется значение 0. Обычно эта проблема решается с помощью настройки веб-сервера, но все равно неприятно.

Сталкиваясь в очередной раз с такой задачей, я в все чаще задумываюсь о том, что генерацией pdf-файлов должен заниматься отдельный микросервис, особенно если проект большой, но это уже совсем другая история.

Пришло время перейти к главной части этой статьи. Помимо вариантов предложенных выше, существует альтернативный - PhantomJS .

PhantomJS - это сборка движка WebKit без графического интерфейса, позволяющая в режиме консоли загружать веб-страницу, выполнять JavaScript, полноценно работать с DOM, Canvas и SVG.

Конечно, помимо перечисленных выше возможностей, он дает возможность создавать pdf-файлы.

Каким образом? Говоря простым языком, он загружает требуемую веб-страницу и дает возможность сохранить результат как pdf-файл.

Процесс установки PhantomJS достаточно подробно описан в документации , поэтому я не буду останавливаться на этом вопросе.

Важным моментом в работе PhantomJS является js-файл (далее config.js), который своим содержанием определяет то, что именно мы хотим сделать. На официальном сайте есть множество готовых примеров таких файлов, с помощью которых решаются самые разные задачи, например, unit-тестирование. В числе примеров есть сохранение веб-страницы в формате pdf . Это именно то, что нам нужно.

Пара небольших правок позволит использовать этот пример в наших целях.

var page = require ("webpage" ). create (), system = require ("system" ), address , output , size ; //если аргументов мало или слишком много, выводится сообщение с помощью по использованию if (system . args . length < 3 || system . args . length > 5 ) { console . log ("Usage: config.js URL filename " ); console . log (" paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"" ); console . log (" image (png/jpg output) examples: "1920px" entire page, window width 1920px" ); console . log (" "800px*600px" window, clipped to 800x600" ); phantom . exit (1 ); } else { // обработка аргументов address = system . args [ 1 ]; output = system . args [ 2 ]; page . viewportSize = { width : 800 , height : 800 }; if (system . args . length > 3 && system . args [ 2 ]. substr (- 4 ) === ".pdf" ) { size = system . args [ 3 ]. split ("*" ); page . paperSize = (size . length === 2 ) ? { width : size [ 0 ], height : size [ 1 ], margin : "0px" } : { format : system . args [ 3 ], orientation : "portrait" , margin : "1cm" }; } else { console . log ("Invalid path to pdf!" ); phantom . exit (1 ); } if (system . args . length > 4 ) { page . zoomFactor = system . args [ 4 ]; } // открытие страницы и сохранение результата page . open (address , function (status ) { if (status !== "success" ) { console . log ("Unable to load the address!" ); phantom . exit (1 ); } else { window . setTimeout (function () { page . render (output ); phantom . exit (); }, 200 ); } }); }

$ phantomjs path/to/config.js "url" path/to/pdf/file "A4"

Разберем аргументы по порядку:

  1. Путь до config.js.
  2. Адрес веб-страницы, которую надо преобразовать в pfd-файл.
  3. Путь до pdf-файла, в который произойдет сохранение результата.
  4. Формат pdf-файла.

Получаем искомый pdf-файл.

Возвращаясь к php, это решение довольно просто интегрировать в код.

В простейшем случае это выглядит вот так:

$command = sprintf( "phantomjs %s %s %s %s", $fullPathToConfigJS, $url, $fullPathToSave, $format ); exec($command);

Итак, подведу итоги. На мой взгляд, такое решение имеет следующие достоинства:

  • Сверстать макет для такого документа намного проще. Это очень важно, т.к. не только упрощает разработку, но и не превращает в кошмар последующие правки документа.
  • Избавляет от нужды извращаться с mbstring.func_overload. Но это, несомненно, проблема характерная в основном для Битрикс.

Конечно, есть и недостатки:

  • Не 100% поддержка всех css-стилей. Но в сравнении с библиотеками, перечисленными в начале стати, все очень хорошо.
  • Такое решение может отпугнуть начинающего разработчика.
03.12.2015

Теперь можно добавить название отчета. Объект FPDF использует концепцию "текущая позиция", куда вставляется следующая часть текста или другой элемент. Так как нужно, чтобы название отчета располагалось в середине страницы, необходимо передвинуть текущую позицию вниз к данной точке, которая располагается на расстоянии 160мм от верха страницы (значение хранится в конфигурационной переменной $reportNameYPos). Для этого используется метод FPDF Ln() , который добавляет перевод строки на указанное расстояние:

$pdf->Ln($reportNameYPos);

Если не указать высоту перевода строки, то будет использоваться высота последней выведенной ячейки.

Теперь добавим название отчета. Существует несколько различных способов добавить текст с помощью FPDF. В нашем случае используем метод Cell() , который, помимо всего прочего, позволяет легко центрировать текст.

Cell() принимает следующие аргументы (все являются опциональными):

  • Высота и ширина ячейки. По умолчанию ширина растягивается до правого поля, а высота устанавливается в 0.
  • Строка текста для вывода. По умолчанию "" .
  • Указание для отображения рамки вокруг ячейки. Это может быть либо число (0 =нет рамки, 1 =рисуем рамку), или строка с одним или несколькими параметрами из следующего списка: "L" (слева), "T" (сверху), "R" (справа), и "B" (внизу). Значение по умолчанию: 0 .
  • Куда помещать текущую позицию после вывода ячейки. Значение может быть 0 (справа от ячейки), 1 (начало следующей строки), или 2 (ниже). Значение по умолчанию: 0 .
  • Выравнивание текста . Возможные значения: "L" (выравнивание по левому краю), "C" (выравнивание по центру), или "R" (выравнивание по правому краю). Значение по умолчанию: "L" .
  • Нужно ли заливать фон ячейки цветом. true = заливаем цветом, false = оставляем фон прозрачным. Значение по умолчанию: false .
  • URL ссылки. Если задан, то ячейка с текстом становится рабочей ссылкой на другой ресурс.

Теперь с помощью метода Cell() вставим название отчета и выровняем его по центру:

$pdf->

Создаем колонтитул страницы и вводный текст

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

Сделаем колонтитул страницы. Добавим новую страницу, затем выведем текст колонтитула, который содержит название отчета, выровнен по центру страницы и использует шрифт Arial размером 17. Используем переменную конфигурации $headerColour для установки цвета текста:

$pdf->AddPage(); $pdf->SetTextColor($headerColour, $headerColour, $headerColour); $pdf->SetFont("Arial", "", 17); $pdf->Cell(0, 15, $reportName, 0, 0, "C");

Теперь перейдем к тексту. Сначала выведем заголовок в обычном цвете и шрифтом Arial размером 20. Так как нам не нужно центрировать текст, можно использовать простой метод Write() , передав ему высоту строки и текст для вывода (в качестве опции можно также передать адрес URL для формирования ссылки):

$pdf->SetTextColor($textColour, $textColour, $textColour); $pdf->SetFont("Arial", "", 20); $pdf->Write(19, "2009 Was A Good Year");

Теперь можно вывести текст введения шрифтом Arial размером 12. Здесь есть пропуски 16 мм от первого абзаца и 12 мм между параграфами. Задаем для каждой строки высоту в 6 мм:

$pdf->Ln(16); $pdf->SetFont("Arial", "", 12); $pdf->Write(6, "Despite the economic downturn, WidgetCo had a strong year. Sales of the HyperWidget in particular exceeded expectations. The fourth quarter was generally the best performing; this was most likely due to our increased ad spend in Q3."); $pdf->Ln(12); $pdf->Write(6, "2010 is expected to see increased sales growth as we expand into other countries.");

Метод Write() автоматически переводит текст на следующую строку, когда он достигает правой стороны страницы.

Добавляем данные

Теперь нужно добавить таблицу с данными ниже текста. сначала установим цвет рамки таблицы. Метод SetDrawColor() устанавливает цвет, который используется для рамок и других линий, так что мы можем использовать его для установки цвета для рамок ячеек таблицы. Затем текущую позицию опускаем вниз на 15мм для создания пробела между текстом и таблицей:

$pdf->SetDrawColor($tableBorderColour, $tableBorderColour, $tableBorderColour); $pdf->Ln(15);

Создаем строку заголовков таблицы

Таблица имеет строку, которая содержит в ячейках заголовки столбцов "PRODUCT", "Q1, "Q2", "Q3", и "Q4". Ячейка "PRODUCT" использует отличный от других заголовков цвет текста и фона.

Мы уже пользовались методом SetTextColor() для установки цвета текста. Для установки цвета фона надо использовать метод SetFillColor() , который имеет такие же аргументы как SetTextColor() .

Чтобы создать ячейки таблицы используется метод Cell() , которому задаются ширина и высота ячейки, содержание и выравнивание. Также передается 1 в качестве 4-го аргумента для установки рамки, и true в качестве 7-го аргумента для заполнения фона установленным цветом.

Ниже приведен код для создания строки заголовков. Сначала устанавливается полужирный шрифт. Затем создается ячейка "PRODUCT" с соответствующим текстом и фоном. Затем устанавливается цвет для оставшихся 4 ячеек заголовков, и выполняется цикл по элементам массива $columnLabels для вывода ячеек с выравниванием текста в них по центру:

// Создаем строку заголовков таблицы $pdf->SetFont("Arial", "B", 15); // Ячейка "PRODUCT" $pdf->SetTextColor($tableHeaderTopProductTextColour, $tableHeaderTopProductTextColour, $tableHeaderTopProductText Colour); $pdf->SetFillColor($tableHeaderTopProductFillColour, $tableHeaderTopProductFillColour, $tableHeaderTopProductFill Colour); $pdf->Cell(46, 12, " PRODUCT", 1, 0, "L", true); // Остальные ячейки заголовков $pdf->SetTextColor($tableHeaderTopTextColour, $tableHeaderTopTextColour, $tableHeaderTopTextColour); $pdf->SetFillColor($tableHeaderTopFillColour, $tableHeaderTopFillColour, $tableHeaderTopFillColour); for ($i=0; $iCell(36, 12, $columnLabels[$i], 1, 0, "C", true); } $pdf->Ln(12);

Пробел в начале содержимого ячейки "PRODUCT" помогает сформировать отступ в ячейке таблицы от левой границы. Такой же трюк будет использоваться для наименований продуктов в крайнем левом столбце (к сожалению, пока нет способа контролировать отступ в ячейках с помощью FPDF).

Создаем строки с данными

Остальная таблица состоит из 4 строк с данными продаж (по одной строке на продукт) для 4-х кварталов. Сначала определим пару переменных:

// Создаем строки с данными $fill = false; $row = 0;

Переменные служат для:

    $fill: Заполнять фон ячейки цветом или нет. Мы будем переключать данное значение после вывода каждой строки для получения эффекта зебры в таблице.

    $row: Текущий номер строки. Она позволяет выводить соответствующий номер для каждой строки при перемещении по таблице.

Теперь можно организовать цикл по элементам массива $data с помощью foreach для вывода строк Для каждой строки создаем левую ячейку, которая содержит название продукта, и четыре ячейки с данными. Устанавливаем соответствующие цвета для тескта и фона для каждой ячейки.

Для вывода ячеек данных используется цикл for для прохода по четырех элементному массиву с данными, а для вывода данных в формате с разделением тысяч вызываем функцию PHP number_format() .

После вывода строки увеличиваем переменную $row , переключаем переменную $fill , и используем Ln() для перехода к началу следующей строки.

Вот код всего цикла:

Foreach ($data as $dataRow) { // Создаем левую ячейку с заголовком строки $pdf->SetFont("Arial", "B", 15); $pdf->SetTextColor($tableHeaderLeftTextColour, $tableHeaderLeftTextColour, $tableHeaderLeftTextColour); $pdf->SetFillColor($tableHeaderLeftFillColour, $tableHeaderLeftFillColour, $tableHeaderLeftFillColour); $pdf->Cell(46, 12, " " . $rowLabels[$row], 1, 0, "L", $fill); // Создаем ячейки с данными $pdf->SetTextColor($textColour, $textColour, $textColour); $pdf->SetFillColor($tableRowFillColour, $tableRowFillColour, $tableRowFillColour); $pdf->SetFont("Arial", "", 15); for ($i=0; $iCell(36, 12, ("$" . number_format($dataRow[$i])), 1, 0, "C", $fill); } $row++; $fill = !$fill; $pdf->Ln(12); }

Создаем график

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

Вычисление масштаба и ширины столбика

Сначала надо вычислить масштаб для осей X и Y. Для масштаба по оси X вычисления заключаются в простом делении количества продуктов на желаемую ширину графика (нужно учесть небольшие отступы слева и справа для лучшего вида):

/*** Создаем график ***/ // Вычисляем масштаб по оси X $xScale = count($rowLabels) / ($chartWidth - 40);

Для вычисления масштаба по оси Y нужно найти общее значение по каждому продукту и затем определить среди них максимальное значение. Затем максимум можно будет разделить на желаемую высоту графика для получения значения масштаба по оси Y:

// Вычисляем масштаб по оси Y $maxTotal = 0; foreach ($data as $dataRow) { $totalSales = 0; foreach ($dataRow as $dataCell) $totalSales += $dataCell; $maxTotal = ($totalSales > $maxTotal) ? $totalSales: $maxTotal; } $yScale = $maxTotal / $chartHeight;

Теперь, зная масштаб по оси X, можно вычислить ширину (в мм) каждого столбца графика. Это инверсированное значение масштаба по оси X, уменьшенное в полтора раза для организации расстояния между столбцами:

// Вычисляем ширину столбцов $barWidth = (1 / $xScale) / 1.5;

Добавляем линии осей и метки на них

Теперь можно добавить линии осей X и Y, метки данных и метки осей. Используем шрифт Arial с размером 10 для меток данных.

Для вывода линии в FDPF используется метод Line() , которые принимает четыре аргумента: координаты X и Y начала линии, и координаты X и Y конца линии.

Для оси X выводим горизонтальную линию вдоль низа графика, оставляя 30 мм для меток по оси Y слева. Затем выводим каждое имя продукта в массиве $rowLabels как текстовую ячейку в соответствующую точку:

// Добавляем оси: $pdf->SetFont("Arial", "", 10); // Ось X $pdf->Line($chartXPos + 30, $chartYPos, $chartXPos + $chartWidth, $chartYPos); for ($i=0; $i < count($rowLabels); $i++) { $pdf->SetXY($chartXPos + 40 + $i / $xScale, $chartYPos); $pdf->Cell($barWidth, 10, $rowLabels[$i], 0, 0, "C"); }

Метод SetXY() позволяет устанавливать текущую позицию в нужное место на странице.

Для оси Y выводим вертикальную линию слева от графика, оставляя 30 мм для меток данных по оси Y. Линию оси делаем на 8 мм больше желаемой высоты графике для того, чтобы было место для вывода метки оси. Затем организуем цикл от нуля до максимального значения данных $maxTotal , которое было определено ранее. Размер шага установлен в переменной $chartYStep (20,000). На каждом шаге выводим текущее значение выровненной вправо и короткую метку:

// Ось Y $pdf->Line($chartXPos + 30, $chartYPos, $chartXPos + 30, $chartYPos - $chartHeight - 8); for ($i=0; $i <= $maxTotal; $i += $chartYStep) { $pdf->SetXY($chartXPos + 7, $chartYPos - 5 - $i / $yScale); $pdf->Cell(20, 10, "$" . number_format($i), 0, 0, "R"); $pdf->Line($chartXPos + 28, $chartYPos - $i / $yScale, $chartXPos + 30, $chartYPos - $i / $yScale); }

Теперь можно добавить метки осей. Используем шрифт Arial полужирный с размером 12. Размещаем метку оси X ниже меток данных, а метку оси Y - наверху оси Y:

// Добавляем метки осей $pdf->SetFont("Arial", "B", 12); $pdf->SetXY($chartWidth / 2 + 20, $chartYPos + 8); $pdf->Cell(30, 10, $chartXLabel, 0, 0, "C"); $pdf->SetXY($chartXPos + 7, $chartYPos - $chartHeight - 12); $pdf->Cell(20, 10, $chartYLabel, 0, 0, "R");

Выводим столбцы графика

Завершающей стадией является создание самого графика. Для вывода столбцов используется метод FPDF Rect() , который выводит прямоугольник. Метод использует следующие аргументы:

  • Координаты X и Y верхнего левого угла прямоугольника.
  • Ширина и высота прямоугольника.
  • Стиль прямоугольника. Может иметь значения "D" или "" (выводим обводку), "F" (заполняем текущим цветом фона), или "DF" / "FD" (обводка и заполнение).

Теперь выводим столбцы. Установим переменную $xPos , которая служит для отслеживания текущей позиции по X. Зададим ей значение 40 мм с учетом расстояния для меток по оси Y и отступа для первого столбца. Теперь создадим переменную $bar , которая будет содержать номер текущего столбца. Она будет использоваться для установки цвета для столбца:

// Создаем столбецы $xPos = $chartXPos + 40; $bar = 0;

Теперь проходим циклом по массиву $data , вычисляем суммарное значение для каждой строки и выводим столбец от оси X до этого значения, масштабированного с помощью $yScale . Цвет для каждого столбца изменяется с помощью счетчика $bar , который является индексом в массиве $chartColours . После вывода текущего столбца перемещаем позицию X к началу следующего, увеличиваем счетчик $bar и продолжаем цикл:

Foreach ($data as $dataRow) { // Вычисляем суммарное значение по строке данных для продукта $totalSales = 0; foreach ($dataRow as $dataCell) $totalSales += $dataCell; // Создаем столбец $colourIndex = $bar % count($chartColours); $pdf->SetFillColor($chartColours[$colourIndex], $chartColours[$colourIndex], $chartColours[$colourIndex]); $pdf->Rect($xPos, $chartYPos - ($totalSales / $yScale), $barWidth, $totalSales / $yScale, "DF"); $xPos += (1 / $xScale); $bar++; }

В коде используется оператор PHP деление по модулю (%) для повтора цвета столбца, если количество столбцов превышает количество элементов в массиве $chartColours .

Отправляем документ PDF браузеру

Документ PDF готов! Осталось только отправить его браузеру, чтобы пользователь мог просмотреть его или загрузить.

Для этого используется метод FPDF Output() . Он принимает два аргумента: предполагаемое имя для PDF файла и флаг назначения. Данный флаг может принимать следующие значения:

    I: Выводить PDF на экран, если такая функция поддерживается браузером, иначе загружать.

    D: Загружать PDF.

    F: Сохранять файл в папке на сервере.

    S: Возвращать данные PDF как строку.

Для нашего примера используется опция I для вывода PDF на экран, если возможно:

/*** Выводим PDF ***/ $pdf->Output("report.pdf", "I"); ?>

Output() автоматически посылает заголовок HTTP "Content-type: application/pdf" , который сигнализирует браузеру о том, что следует ожидать документ PDF.

Теперь вы готовы протестировать скрипт. Открывайте браузер и переходите на URL, где расположен скрипт, например, www.example.com/report.php . Вы должны увидеть PDF в окне браузера. Или будет выведено диалоговое окно, в котором вам будет предложено сохранить документ PDF на вашем жестком диске. Вы можете потом открыть PDF файл в программе для просмотра PDF, например, в Acrobat Reader или Preview.

Для создания PDF документа нужен только PHP и FPDF.

Заключение

В данном уроке вы узнали как использовать PHP с библиотекой FPDF для генерации отчета в формате PDF. Были продемонстрированы методы библиотеки FPDF для создания текста, таблиц и графиков.

Однако библиотека FPDF может много чего еще, например, создавать верхний и нижний колонтитулы для страниц, использовать автоматический переход на новую страницу и так далее. Просмотрите документацию по библиотеке на сайте FPDF .

PDF (portable document format) - это популярный формат документов, который не зависит от операционной системы или железа. Очевидно, его можно использовать для генерации отчетов, дипломов, чеков в приложениях, а так же для редактирования документов. Для этих целей лучше всего подойдет java-библиотека iText . Кстати, библиотека доступна так же и для C#.

В статье мы рассмотрим следующие вопросы:

  • Генерация нового PDF документа на примере чека.
  • Заполнение шаблона PDF документа.
  • Краткий обзор некоторых классов и методов библиотеки iText.

Для нетерпеливых сразу же привожу java код, который создает pdf-шаблон чека, а потом заполняет его данными из объекта Receipt. Не забудьте скачать jar-файл библиотеки и положить его на classpath.

Import com.itextpdf.text.*; import com.itextpdf.text.pdf.*; import java.io.FileInputStream; import java.io.FileOutputStream; import java.net.URL; import java.text.NumberFormat; import java.util.Date; public class PdfGeneration { static int FONT_SIZE_SMALL = 16; static int FONT_SIZE_BIG = 32; static int OFFSET = 40; public static void main(String args) throws Exception { createTemplate(); Receipt receipt = new Receipt("This is a veeeeeeeeeeeeeeeeeeeeee" + "eeeeeeeeeeeeeeeeeeeeery long purpose " + "text, so it will overflow with font size = 16", 123.45, "Name Surname"); fillInReceipt(receipt); } public static void createTemplate() throws Exception { Document document = new Document(); Font font1 = new Font(Font.FontFamily.HELVETICA, FONT_SIZE_BIG, Font.BOLD); Font font2 = new Font(Font.FontFamily.HELVETICA, FONT_SIZE_SMALL, Font.ITALIC | Font.UNDERLINE); PdfWriter.getInstance(document, new FileOutputStream("template.pdf")); document.open(); // отцентрированный параграф Paragraph title = new Paragraph("Receipt", font1); title.setAlignment(Element.ALIGN_CENTER); title.setSpacingAfter(FONT_SIZE_BIG); document.add(title); // параграф с текстом Paragraph purpose = new Paragraph("Purpose", font2); purpose.setSpacingAfter(FONT_SIZE_BIG); document.add(purpose); // параграф с добавленным чанком текста Paragraph amount = new Paragraph(); amount.setFont(font2); amount.setSpacingAfter(8); amount.add(new Chunk("Amount")); document.add(amount); // параграф с фразой, в которую добавлен чанк Paragraph date = new Paragraph(); date.setFont(font2); Phrase phrase = new Phrase(); phrase.add(new Chunk("Date")); date.add(phrase); document.add(date); document.add(new Paragraph("Name", font2)); Paragraph footer = new Paragraph("Important - please retain for your records - "); // ссылка Anchor anchor = new Anchor("Javenue"); anchor.setReference("http://www..add(anchor); footer.setAlignment(Element.ALIGN_CENTER); footer.setSpacingBefore(FONT_SIZE_BIG); document.add(footer); // картинка, загруженная по URL String imageUrl = "http://www..png"; // Image.getInstance("sample.png") Image stamp = Image.getInstance(new URL(imageUrl)); stamp.setAlignment(Element.ALIGN_RIGHT); document.add(stamp); document.close(); } public static void fillInReceipt(Receipt receipt) throws Exception { PdfReader reader = new PdfReader(new FileInputStream("template.pdf")); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("receipt.pdf")); PdfContentByte stream = stamper.getOverContent(1); stream.beginText(); stream.setColorFill(BaseColor.BLUE); BaseFont font = BaseFont.createFont(); float pageWidth = reader.getPageSize(1).getWidth(); stream.setFontAndSize(font, FONT_SIZE_SMALL); float v = stream.getEffectiveStringWidth(receipt.getPurpose(), false); float fitSize = (pageWidth-OFFSET*2) * FONT_SIZE_SMALL/v; stream.setFontAndSize(font, fitSize); stream.setTextMatrix(OFFSET, 680); stream.showText(receipt.getPurpose()); stream.setFontAndSize(font, FONT_SIZE_SMALL); String amount = NumberFormat.getCurrencyInstance() .format(receipt.getAmount()); v = stream.getEffectiveStringWidth(amount, false); stream.setTextMatrix(pageWidth - v - OFFSET, 655); stream.showText(amount); v = stream.getEffectiveStringWidth(receipt.getDate() + "", false); stream.setTextMatrix(pageWidth - v - OFFSET, 630); stream.showText(receipt.getDate() + ""); v = stream.getEffectiveStringWidth(receipt.getName(), false); stream.setTextMatrix(pageWidth - v - OFFSET, 605); stream.showText(receipt.getName()); stream.endText(); stamper.setFullCompression(); stamper.close(); } static class Receipt { private String purpose; private double amount; private Date date = new Date(); private String name; public Receipt(String purpose, double amount, String name) { this.purpose = purpose; this.amount = amount; this.name = name; } public String getPurpose() { return purpose;} public void setPurpose(String purpose) { this.purpose = purpose; } public double getAmount() { return amount; } public void setAmount(double amount) { this.amount = amount; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getName() { return name; } public void setName(String name) { this.name = name; } } }

Для начала необходимо создать экземпляр com.itextpdf.text.Document и с помощью PDFWriter связать его с файлом на файловой системе. Создать шрифт можно с помощью класса Font, указывая размер шрифта, его семейство и стиль.

Основные объекты, с которыми вы будете работать, это Phrase, Paragraph, возможно Anchor и самый маленький кусок текста - Chunk. Обратите внимание, что для каждого параграфа вы можете задать свой шрифт и далее добавлять в параграф объекты Chunk, Phrase, Anchor.

C помощью следующего кода можно добавить картинку в PDF документ:

String imageUrl = "http://site.com/image.png"; Image stamp = Image.getInstance(new URL(imageUrl)); stamp.setAlignment(Element.ALIGN_RIGHT); document.add(stamp);

Не забудьте вызвать document.close() после добавления всех объектов. Это необходимо для того, чтобы корректно закрыть PDFWriter.

Писать поверх существующего PDF документа можно через PdfContentByte. Немного придется помучиться с расположением текста на чеке, но кто говорил, что будет легко. Думаю, код метода fillInReceipt понятен и не требует дополнительных объяснений.

А вот еще классы из iText API, которые могут вам пригодиться:

  • List и ListItem - это список и элемент списка, который может быть добавлен как list.add(new ListItem("item")). Списки как и в HTML могут быть упорядоченные и неупорядоченные.
  • Chapter и Section - раздел и соответственно его секция. Секции можно добавлять с помощью вызова chapter.addSection
  • Более сложный объект PdfPTable, состоящий из ячеек PdfPCell. Можно делать достаточно красивые таблички, но как по мне API не самый удобный.

Вот и все. Если есть вопросы - обращайтесь: всегда рад помочь.