Генерируем PDF с помощью TCPDF
Сегодня рассмотрим возможность создания PDF-файла из скрипта на PHP. Зачем нам нужно создавать PDF? Существует множество разных ситуаций, в которых это необходимо, но мы знаем точно одно – PDF как никакой другой формат отлично обеспечит точность отображения представленной в нем информации на листе бумаги. Другими словами, если мы хотим, чтобы некий документ распечатался правильно на любой системе, мы должны его подготовить в формате PDF.
Когда необходимость создать документ из PHP застала и меня, я бросился на поиски готовых решений и рассмотрел три наиболее популярных с моей точки зрения решения (может быть я и ошибаюсь):
- Расширение PDFLib для PHP (http://www.pdflib.com)
- Библиотека FPDF (http://www.fpdf.org/)
- Библиотека TCPDF (http://www.tcpdf.org/)
Погуляв по различным форумам и почитав про PDFLib, я решил ее не использовать, поскольку она не поддерживает UTF-8 (насколько я понял, поддерживает только платная версия), а мне именно такая возможность и была нужна. Также это расширение должно быть установлено на хостинге, где будет работать PHP-скрипт, что тоже ограничивает сферу применения скрипта.
Не зная еще про то, что FPDF тоже не поддерживает UTF-8 (но не требует дополнительных расширений для PHP), я первым делом взялся за нее, но потом тоже отбросил по понятной причине.
В итоге я узнал о библиотеке TCPDF, которая имеет поддержку UTF-8, что мне было необходимо, и которая не требовательна к функциям хостинга.
Итак, попытаемся на ее основе сгенерировать простой PDF-документ на русском языке, который будет отображаться везде (даже на тех компьютерах, где нет нужных шрифтов).
Руководство по использованию этой библиотеки я дублировать здесь не буду
. Вы с успехом сможете найти его на сайте http://www.tcpdf.org/. Там же есть примеры использования этой библиотеки с исходными кодами. Честно говоря, руководства как такового там нет, но есть справка по всем функциям и классам (http://www.tecnick.com/pagefiles/tcpdf/doc/index.html), а также различные примеры, как я уже писал предложением ранее. Из того, что там дано, несложно понять, что и как делается. Но справка по функциям, честно сказать, не очень удобна (видимо формировалась автоматически на основе комментариев в коде библиотеки).
Цель данного поста – показать, как эту библиотеку использовать, и рассказать о ньюансах использования шрифтов.
Пусть наш документ будет содержать в себе простое предложение – «Привет, Мир!», окрашенное в зеленый цвет и содержащееся в синей рамке. Пусть это предложение вместе с рамкой будет отцентрировано по горизонтали и выведено в начале листа формата A4. Мы предполагаем, что на компьютере, где этот документ будут читать, нет шрифта Arial, на котором мы напишем «Привет, Мир!» (всякое бывает), поэтому мы научимся подготавливать шрифты для их вставки в PDF, чтобы документ был автономным.
Итак, скачиваем с официального сайта библиотеку и подключаем ее, дописав несколько строк кода, которые «нарисуют» нам наш документ (предполагается, что директория tcpdf находится на одном уровне с нашим скриптом):
<?php
require_once 'tcpdf/tcpdf.php'; // подключаем библиотеку
// создаем объект TCPDF - документ с размерами формата A4
// ориентация - книжная
// единицы измерения - миллиметры
// кодировка - UTF-8
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
// убираем на всякий случай шапку и футер документа
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetMargins(20, 25, 25); // устанавливаем отступы (20 мм - слева, 25 мм - сверху, 25 мм - справа)
$pdf->AddPage(); // создаем первую страницу, на которой будет содержимое
$pdf->SetXY(90, 10); // устанавливаем координаты вывода текста в рамке:
// 90 мм - отступ от левого края бумаги, 10 мм - от верхнего
$pdf->SetDrawColor(0, 0, 200); // устанавливаем цвет рамки (синий)
$pdf->SetTextColor(0, 200, 0); // устанавливаем цвет текста (зеленый)
$pdf->Cell(30, 6, 'Hello, World!', 1, 1, 'C'); // выводим ячейку с надписью шириной 30 мм и высотой 6 мм. Строка отцентрирована относительно границ ячейки
$pdf->Output('doc.pdf', 'I'); // выводим документ в браузер, заставляя его включить плагин для отображения PDF (если имеется)
?>
Сейчас мы вывели строку «Hello, World!», поскольку по-русски мы пока вывести ничего не можем, т.к. шрифт используется стандартный – helvetica – без поддежки UTF-8.
Теперь подготовим шрифт Arial с кодировкой UTF-8. Условимся, что нам нужен пока только этот шрифт с начертанием «нормальный» (бывает еще жирный, курсивный, жирный курсив).
В TCPDF делается это не очень удобно (я бы даже сказал, очень неудобно), но скажем спасибо создателю, что хоть такая возможность есть
Все шрифты, готовые к использованию в TCPDF хранятся в папке fonts внутри директории библиотеки. Открыв ее, мы увидим множество файлов разных расширений (кстати, эта папка весит более 12 метров). Удалим все файлы, оставив только helvetica.php (т.к. она используется по умолчанию и если мы ее удалим, TCPDF работать не будет) и папку utils (она нам понадобится для подготовки файлов шрифта Arial). Теперь берем шрифт Arial (начертание – normal) из системной папки Windows (у меня Vista) – файл arial.ttf – и копируем его в папку fonts/utils.
В этой папке есть утилита ttf2ufm, которой мы должны скормить файл arial.ttf:
ttf2ufm -a -F arial.ttf
Далее запускаем скрипт makefont.php (предполагается, что путь к php есть в переменной окружения PATH системы):
php -q makefont.php arial.ttf arial.ufm
После работы данной утилиты у нас в папке utils появятся три файла: arial.php, arial.z, arial.ctg.z, которые мы должны будем переместить в папку fonts. Файлы arial.ttf и arial.ufm нам больше не нужны, поэтому можем смело их удалять.
В итоге мы подготовили шрифт Arial, который будет присоединен к формируемому PDF-файлу. Попробуем теперь вывести надпись по-русски:
<?php
require_once 'tcpdf/tcpdf.php'; // подключаем библиотеку
// создаем объект TCPDF - документ с размерами формата A4
// ориентация - книжная
// единицы измерения - миллиметры
// кодировка - UTF-8
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
// убираем на всякий случай шапку и футер документа
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetMargins(20, 25, 25); // устанавливаем отступы (20 мм - слева, 25 мм - сверху, 25 мм - справа)
$pdf->AddPage(); // создаем первую страницу, на которой будет содержимое
$pdf->SetXY(90, 10); // устанавливаем координаты вывода текста в рамке:
// 90 мм - отступ от левого края бумаги, 10 мм - от верхнего
$pdf->SetDrawColor(0, 0, 200); // устанавливаем цвет рамки (синий)
$pdf->SetTextColor(0, 200, 0); // устанавливаем цвет текста (зеленый)
$pdf->SetFont('arial', '', 9); // устанавливаем имя шрифта и его размер (9 пунктов)
$pdf->Cell(30, 6, 'Привет, Мир!', 1, 1, 'C'); // выводим ячейку с надписью шириной 30 мм и высотой 6 мм. Строка отцентрирована относительно границ ячейки
$pdf->Output('doc.pdf', 'I'); // выводим документ в браузер, заставляя его включить плагин для отображения PDF (если имеется)
?>
Но при этом нужно учесть, что размер формируемого PDF-документа возрастет примерно на размер файла шрифта arial.z.
Также необходимо учесть, что если мы хотим вывести надпись курсивно, нам нужно будет для этого создавать отдельный шрифт ariali, или если полужирным начертанием – arialb.
В этом конечно заключается недостаток библиотеки – чем больше шрифтов используем в PDF-документе, тем он больше «весит». Создатели этой библиотеки приводят метод использования шрифтов, установленных в системе, без их присоединения к PDF-документу, но лично у меня ничего не получилось (прочитать о том, как готовить шрифты для PDF, можно в файле README.txt, который находится в папке fonts/utils).
Но с другой стороны, если мы хотим быть уверены, что получатель нашего документа прочитает его, мы должны присоединить шрифт к документу, как проделывали это выше. К тому же, если это документ в буквальном смысле слова (например, платежное поручение), то шрифтов там должно использоваться по минимуму.
Кстати, забыл написать, что TCPDF разработана как для PHP4, так и для PHP5.
А вот и получившийся документ: doc.pdf
Думаю, эта статья поможет кому-то сэкономить время на изучение этой великолепной библиотеки TCPDF
P.S. Если кто-то знает способ формирования PDF лучший (и более удобный), чем тот, что я привел – прошу в комменты
Буду рад узнать о других возможностях.
Июнь 8th, 2009
О, спасибо! Я как-то уже поднимал подобную тему, остановился на
Июнь 10th, 2009
Полгода назад я прошел точно такой же “путь по борьбе” с PDF на PHP
Единственная странность – чересчур большой размер документа на выходе. Т.е. понятно, что в документ включены шрифты, но у меня, простейший 2-х страничный отчет о работе менеджера (2 шрифта, 4 картинки) весил под 1.5 Мб.
Июнь 10th, 2009
Видимо с этим ничего не поделаешь – из-за размера приходится ограничиваться в шрифтах.
Июнь 12th, 2009
А у Zend Framework есть отдельный класс . Использовать еще не приходилось, но в документации написано буквально следующее:
Модуль Zend_Pdf является механизмом для работы с PDF (Portable Document Format — переносимый формат документов), который написан целиком на PHP 5.
Приходилось работать?
Июнь 13th, 2009
К сожалению, не приходилось. Судя по описанию, тоже достаточно мощная библиотека для работы с PDF. У нее, видимо, даже есть возможность модифицировать ранее созданные PDF-файлы, что является преимуществом перед другими библиотеками.
Июнь 13th, 2009
Приходилось работать с ZendPdf но еще на весрии 1.5 и были очень большие тормоза при создании файла…т.е. когда уже все определнео и идет всего этого обработка и запись в файл. TCPDF в плане скорости показал себя лучше.
Замеров не проводил, чисто по визуальному опредлению
Июнь 21st, 2009
спасибо за статью. будет с чего начать
>>но у меня, простейший 2-х страничный отчет о работе менеджера (2 шрифта, 4 картинки) весил под 1.5 Мб.
а нету ли гденить в настройках скрипта чтобы задавать сжатие картинок или сокращение знакового состава шрифтов (font substitution) ?
Июнь 21st, 2009
извиняюсь – сокращение знакового состава – это subset font
тут в самом конце есть чтото
сейчас попробую осмыслить….
Июнь 21st, 2009
ZlyddeN, по поводу сжатия картинок – попробуйте функцию setJPEGQuality. Сокращение знакового состава конечно дает уменьшение веса шрифта, но необходимо только в том случае, если Вы уверены, что будете использовать только символы определенной кодировки (на определенном языке). Если же предполагается, что шрифт будет использоваться для разных языков, то этого лучше не делать.
Июнь 21st, 2009
>>
что будете использовать только символы определенной кодировки (на определенном языке). Если же предполагается, что шрифт будет использоваться для разных языков, то этого лучше не делать.
>>
я предполагал по аналогии с Acrobat Distiller – он перед внедрением в PDF сокращает знаковый состав до нужного минимума (задается в настройках). А тут как?
Июнь 21st, 2009
Тут конечно нет автосокращения знакового состава. Можно сократить его вручную – инструкция по ссылке выше, оставленной вами, ZlyddeN.
Июнь 22nd, 2009
>>Можно сократить его вручную
пришел к выводу, что для моей задачи это не требуется
но… зачем вручную.. можно к примеру каждый раз генерить шрифт с нужным знаковым составом, предварительно проанализировав текст… тока вот утилитка ttf2ufm она только пот Windows?
Июнь 22nd, 2009
Она под Windows, но к ней прилагаются исходники, поэтому можно перекомпилировать под Linux.
Июнь 22nd, 2009
колдовал сегодня с параметрами и шрифтами.
дано: $text в cp1251
требуется: сделать из этого PDF с использованием Times
проблема: шрифт идущий со скриптом не переваривает криллицу
решение:
1. создавать объект так:
$pdf = new TCPDF(’P', ‘mm’, ‘A4′,false, ‘UTF-8′, false);
2. генерить по мануалу шрифт, НО запускать makefont так:
php -q makefont.php times.ttf times.afm true cp1251
Июнь 22nd, 2009
3. полученные times.php и times.z перенести с заменой в папку со шрифтами
Июнь 23rd, 2009
может кому и сгодится – вся семья Times тут
Ссылка для скачивания файла:
Июль 17th, 2009
Зря вы так сразу FPDF отбросили
С UTF8 не пробовал, но если сконвертировать кириллические шрифты (описано в мануале), то проблем с кириллицей нет. Подозреваю, что и с UTF8 тоже не должно быть. Пара шрифтов под FPDF и подобный тьюториал –
Июль 20th, 2009
очень хорошая статья! У меня возник только один вопрос как я могу в уже имеющийся файл дописать информацию?
Заранее спасибо!
Июль 20th, 2009
С помощью TCPDF – никак. Я и сам был бы рад узнать способ, если он существует.
Август 13th, 2009
Огромное спасибо!!
Провел 3 дня в поисках решения генерации pdf с поддержкой юникода. Эта статья мне очень помогла
Сентябрь 17th, 2009
Кстати, метод описанный в README.txt папки fonts\utils работает!
Мне удалось уменьшить размер минимального документа до 65 кб! Главное – в полученном .php файле шрифта закомментировать строчку “$file=…” и использовать только стандартные шрифты без пробелов в названии.
Октябрь 8th, 2009
Всем вечер добрый!
Сейчас возникла нужда в пдф…. а именно bp excel->pdf что то не нашел у tcpdf этого текст выводит даже любыми цветами это все замечательно но нужно именно excel->pdf!!!
Если знаете как скиньте ссылку благодарности не будет предела
с ув. germani
Октябрь 9th, 2009
про Статью спасибо, но выбрав для себя tcpdf для реализации задачи, столкнулся с постоянными ошибками.
Все хорошо, когда читаешь описание, смотришь примеры и документацию. Когда начинаешь что-нибудь реализовывать начинаются ошибки при открытии файла acrobate reader’ом. Особенно из-за шрифтов. Видимо внутри не хватает проверок на всякие исключения.
Еще не понял как сделать таблицу при не одинаковой высоте ячеек. При автоматическом подборе высоты, ячейка получается с бОльшей высотой.
Октябрь 13th, 2009
Было бы хорошо все в chain’ах делать в библиотеке этой
Октябрь 20th, 2009
спасибо за статью, мне как раз не стало хватать уникода в fpdf, да и кодировку 1251 вручную там надо прописывать.
к нему надстройка ufpdf имеется, но ее так и не заставил нормально отображать русские символы.
тыкнулся еще в pear’овский file_pdf, но tcpdf сразу гораздо лучше показался
Ноябрь 9th, 2009
Работал с ZendPdf. Отличная библиотека, если используюте ZF то лучьшего выбора не найти. Начиная с версии 1.6 тормозов за ней не замечал. Хотя в некоторых случаях тормоза зависят от сервера и документа конечно.
Ноябрь 25th, 2009
использую FPDF, но совет
>>закомментировать строчку “$file=…”
помог, но стала выскакивать ошибка при открытии pdf-ника что невозможно найти встроенный шрифт, но русский отобразился без проблем
размер файла упал с 250кб до 40кб – что не может не радовать
описанную мной ошибку я обшел: не закоментировал строчку а прировнял к пустой строке $file=”
и все работает на ура!!
Ноябрь 26th, 2009
Статья очень помогла, продукт работает

Правда не очень разобрался с качеством картинок – они как-то замыливаются в получаемом файле. Параметр setJPEGQuality (50-75-100) не влияет на качество – только размер немного экономит. Но больше всего меня напрягает высокая нагрузка сервера – файл на 40 листов (~200 картинок + текст 1 шрифт – генерится примерно 40 сек) грузит проц на 46%
Соответственно 2 клиента с таким заданием загонят его под 100%…
Я конечно понимаю, что десктопное железо не есть сервер…но как-то многовато имхо. Никто не смотрел у себя нагрузку?
Январь 6th, 2010
Спасибо, оч клевая статья.
Злыдень, а выложи шрифты которые ты скомпилировал? Ариал под утф – вот это поможет еще больше. Спасибо.
Январь 8th, 2010
не как не могу понять как изменить стандартный шрифт и чтоб он понимал кирилицу… И еще как правильно собрать шрифт с помощью makefont.php на локальном компьютере?
Январь 27th, 2010
Тут мною написанный скрипт генерации шрифтов для TCPDF:
narod.ru/disk/17313273000/TCPDF_MakeRusFontsScript_1.0.rar.html
В архиве есть описание “ReadMe_TCPDF_MakeRusFontsScript_1.0.txt”. Почитайте, постарался подробно описать.
Также в архив уже включен шрифт “Arial” с кириллицей.
К сожалению, вывод напрямую в CP1251 победить не удалось, поэтому в работе использую “iconv(’CP1251′, ‘UTF-8′, …)” для выводимого в TCPDF текста.
Январь 28th, 2010
супер статья, все помогло. я в основном перегоняю картинки в пдф – так вот эта tcpdf тормозит порядочно, но работает. и для картинок пришлось на хостинге увеличить оперативки лимит до 100Мб и с 30 сек до 5 минут поднять время выполнения скрипта (но в принципе за 3 минуты справляется). после этого как часы работает. я так понимаю все тормоза и ресурсы идут на перегонку jpg под формат листа А4. спасибо.
Февраль 4th, 2010
Спасибо, Ваша статься очень помогла. Хорошо написана, и прочитав пару абзаыев, выполняя всё, создал шрифт и перенёс всё с fpdf на tcpdf. Теперь у меня и русские и французкие буквы нормально отображаются в utf-8.
Спасибо