PDF24 Creator, это бесплатный PDF генератор для вашего ПК. Генерация PDF файлов невероятно простая задача с этой программой. Комбинация дополнительных возможностей вместе с созданием PDF файлов, делает этот инструмент одной из самых признанных бесплатных программ. В качестве альтернативы вы также можете генерировать PDF онлайн. Прочтите ниже как это работает.
PDF24 Creator – бесплатный PDF генератор
PDF24 Creator, это бесплатный PDF генератор для Windows. Генерация PDF файлов реализована с помощью PDF принтера. После установки в вашей Windows появится новый виртуальный PDF принтер. Просто печатайте через этот принтер все, что хотите превратить в PDF. PDF принтер, это единственный путь создания PDF. Программа включает в себя широкий диапазон возможностей, которые помогут вам в генерации PDF. Эта программа бесплатна. Вы можете скачать свежую версию с этого сайта.
PDF24 Онлайн PDF Генератор – Генерация PDF файлов онлайн
Онлайн PDF Генератор, это полезный инструмент, если вы хотите преобразовать документы в PDF формат. Просто выберите документ или отправьте документ по почте в Онлайн PDF Генератор и через несколько секунд ваш PDF файл будет доступен для скачивания или отправлен вам обратно.
Email интерфейс для этого PDF генератора также доступен. Нужно отправить файлы генератору и дождаться ответного письма, в котором будут файлы, сконвертированные в PDF
Множество других PDF генераторов в инструментарии PDF24
Онлайн утилиты от PDF24 решают многие проблемы, связанные с PDF, достаточно просто, быстро и бесплатно. Многие из этих инструментов генерируют PDF файлы. Вы ещё не знакомы с онлайн утилитами PDF24? Взгляните, вы сможете использовать все эти инструменты.
Где это может пригодиться? При необходимости генерации готовых к печати файлов в 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 объекта рисунка прописать строку:
где {IMAGE} - это поле для вставки шаблонизатором base64 кодированного изображения.
Для примера нарисуем простенький шаблон бейджа, думаю вы меня простите за кривость, я не художник, а для реального использования, вы можете заказать у вашего дизайнера векторный макет.
Я не стал использовать изменяемое растровое изображение, оставив это на домашнее задание, а ограничился лишь изменяемыми текстовыми полями.
Думаю, вы уже обратили внимание на то, что в местах предполагаемого текста вставлены тэги шаблонизатора (в данном примере использовался ). Именно использование XML совместимых тегов дает возможность прописывать их в самом векторном редакторе не прибегая к дополнительному редактированию.
Мы имеем шаблон, и уже без проблем сможем вставить необходимые нам данные, но как собственно мы будем проводить преобразование? Для этого воспользуемся интерфейсом командной строки Inkscape:
#преобразование в PDF-файл
inkscape -A
Используя ключ «-A » мы сразу получим PDF файл, но, к сожалению, создаваемый напрямик PDF имеет очень большие размеры. Для решения этой проблемы можно пойти в обход. А именно, использовать экспорт SVG не на прямую в PDF, а по цепочке SVG->PS->PDF . Использовав для конечного формирования PDF файла утилиту ps2pdf из комплекта Ghost Script, мы можем уменьшить размеры финального файла в десятки раз.
#преобразование в PostScript-файл
inkscape -P
#преобразование в PostScript-файла в PDF
ps2pdf
Единственный минус в том, что в этом случае мы потеряем все эффекты прозрачности, так как формат PostScript его не поддерживает.
Для полной переносимости сгенерированных документов, можно добавить Inscape’у опцию «-T » преобразования всего текста в кривые. Этим самым мы сможем избавиться от проблем наличием шрифтов на клиентской машине, а также от проблем с кодировками.
Теперь мы имеем, всё необходимое: SVG шаблон и команды преобразований. Напишем php-скрипт, который бы выдавал pdf-файл сгенерированный из шаблона.
/* ****************************************************************************************
* Скрипт формирования 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//Ключи
system («ps2pdf -dUseFlateCompression=true -dPDFSETTINGS=/printer $tmp_ps_file $tmp_pdf_file» , $success );//в случае неудачного выполнения преобразования формируем исключение
// -dUseFlateCompression=true - устанавливает использование компрессии
// -dPDFSETTINGS=/printer - устанавливает оптимизацию для печати
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" );
}
?>
Думаю, всем не составит особого труда переписать скрипт на другом языке программирования.
Одной из важных частей любой системы управления проектами является возможность сделать отчёт о текущем положении дел. Это позволяет точнее оценивать текущее состояние дел. Для пользователей такой отчёт может быть не только аналитикой нужной для работы, но и своеобразной формой отчётности. Поэтому в компании Revizto уделяют большое внимание технической стороне генерации отчётов.
У отдельных клиентов отчёты представляют из себя большие pdf на десятки тысяч страниц. Само собой такие отчёты весят гигабайты и генерация их занимает продолжительное время. Столкнувшись с очередным ростом размера отчёта, мы решили проанализировать нашу архитектуру генерации pdf.
Традиционно в вебе генерация pdf состоит из двух этапов:
- Генерация html страницы, которая потом станет pdf
- Перевод html в pdf
Первый этап в нашем случае занимал достаточно мало времени, а вот второй мог длиться больше часа. Поэтому мы сделали небольшое сравнение какие существуют опенсорсные возможности по генерации pdf:
- Wkhtmltopdf Command exited with non-zero status 1 Command being timed: "wkhtmltopdf 1.html 1.pdf" User time (seconds): 3356.13 System time (seconds): 7.12 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 56:21.54 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 3457744 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 8 Minor (reclaiming a frame) page faults: 977440 Voluntary context switches: 38567 Involuntary context switches: 47975 Swaps: 0 File system inputs: 1240 File system outputs: 197480 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 1
Command being timed: "phantomjs --ssl-protocol=any ./capture.js 1.html 1.pdf" User time (seconds): 2240.56 System time (seconds): 6.96 Percent of CPU this job got: 83% Elapsed (wall clock) time (h:mm:ss or m:ss): 44:35.89 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 1821840 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 28 Minor (reclaiming a frame) page faults: 489364 Voluntary context switches: 53462 Involuntary context switches: 31797 Swaps: 0 File system inputs: 4576 File system outputs: 233848 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
Command being timed: "/usr/bin/google-chrome-stable --headless --disable-gpu --print-to-pdf 1.html" User time (seconds): 54.22 System time (seconds): 7.32 Percent of CPU this job got: 5% Elapsed (wall clock) time (h:mm:ss or m:ss): 18:49.74 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 951796 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 2 Minor (reclaiming a frame) page faults: 938614 Voluntary context switches: 184497 Involuntary context switches: 37463 Swaps: 0 File system inputs: 368 File system outputs: 174352 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
Из преведенного теста видно, что лучший результат получается у chrome, потом в два раза хуже phantomJs, а потом ещё значительно хуже Wkhtmltopdf. Этот результат перекликается с проблемами с разработкой phantomJs
C другой стороны chrome зависит от X11, так что на сервере вопросов с ним будет значительно больше чем с phantomJs.
Если делать небольшой вывод, то для тестирования машине с десктопом chrome безусловный победитель. На сервере его разумно использовать, если не бояться поставить туда X11, иначе phantomJs будет оптимальным вариантом
Генерация 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"
Разберем аргументы по порядку:
- Путь до config.js.
- Адрес веб-страницы, которую надо преобразовать в pfd-файл.
- Путь до pdf-файла, в который произойдет сохранение результата.
- Формат pdf-файла.
Получаем искомый pdf-файл.
Возвращаясь к php, это решение довольно просто интегрировать в код.
В простейшем случае это выглядит вот так:
$command = sprintf( "phantomjs %s %s %s %s", $fullPathToConfigJS, $url, $fullPathToSave, $format ); exec($command);
Итак, подведу итоги. На мой взгляд, такое решение имеет следующие достоинства:
- Сверстать макет для такого документа намного проще. Это очень важно, т.к. не только упрощает разработку, но и не превращает в кошмар последующие правки документа.
- Избавляет от нужды извращаться с mbstring.func_overload. Но это, несомненно, проблема характерная в основном для Битрикс.
Конечно, есть и недостатки:
- Не 100% поддержка всех css-стилей. Но в сравнении с библиотеками, перечисленными в начале стати, все очень хорошо.
- Такое решение может отпугнуть начинающего разработчика.
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 не самый удобный.
Вот и все. Если есть вопросы - обращайтесь: всегда рад помочь.