Сообщить об ошибке.

Преобразование HTML в PDF используя модуль fpdf2 в Python

Преобразование базового HTML в PDF-документ

Модуль fpdf2 поддерживает базовый рендеринг из HTML. Другими словами fpdf2 поддерживает конвертацию/преобразование HTML-разметки в PDF-документ. Это очень удобно, когда надо быстро создать небольшой и не сложный PDF-документ.

Разбор HTML реализуется с помощью класса html.parser.HTMLParser из стандартной библиотеки Python, а преобразование в PDF происходит с помощью класса fpdf.HTMLMixin. Конечно, вся спецификация HTML не поддерживается, CSS не поддерживается от слова "совсем". В общем преобразование HTML-разметки в PDF-документ работает не стабильно и не совсем так как ожидаешь, но отчеты об ошибках и предложения по улучшению командой разработчиков приветствуются.

Поддерживаемые HTML-теги модулем fpdf2:

  • от <h1> до <h8>: заголовки и его атрибут выравнивания align;
  • <p>: абзац и его атрибут выравнивания align;
  • <br>: перенос строки;
  • <b>, <i>, <u>: жирный шрифт, курсив, подчеркивание (и их сочетание);
  • <font>: установка шрифта для HTML и его атрибуты face, size, color;
  • <center> для выравнивания по центру;
  • <a>: ссылка и его атрибут href;
  • <img>: изображения и атрибуты тега src, width, height;
  • <ol>, <ul>, <li>: упорядоченные, неупорядоченные элементы и элементы списка (могут быть вложенными);
  • <table>: тег таблицы и его атрибуты border=1, width;
    • <thead>: заголовки колонок таблицы;
    • <tbody>: фактические строки с колонками;
    • <tfoot>: нижний колонтитул (должен завершать строки с колонками, используется перед закрывающим </table>);
    • <th>: заголовки ячейки с ее атрибутами align, bgcolor, width;
    • <tr>: строка таблицы с атрибутом bgcolor;
    • <td>: ячейка с ее атрибутами align, bgcolor, width;

Важно:

  • Тег таблицы <table> может иметь атрибут width, указанный только в процентах от ширины листа. При этом таблица центрируется по середине. Если ширина width не указана, то таблица выравнивается по левому краю.
  • Все таблицы должны иметь как минимум первую строку (заголовок таблицы) <th> с указанием атрибута ширины width каждой колонки (указывается в % или единицах, указанных при создании объекта FPDF (по умолчанию unit="mm" миллиметры).
  • При использовании в <table> атрибута border=1 (отображение рамки) в сочетании с центрированием, например width=80%, для корректного отображения нижней границы, последняя строчка таблицы, перед ее закрытием должна содержать пустой подвал <tfoot><tr></tr></tfoot>.

Примечание: Для более надежного и полнофункционального преобразования HTML5 + CSS3 в PDF-документ на Python можно использовать сторонний модуль WeasyPrint, PyPi. Модуль имеет много зависимостей, но делает потрясающие PDF-документы из HTML.

Пример добавления содержимого HTML на PDF-страницу при помощи fpdf2.

from fpdf import FPDF, HTMLMixin, __version__ as ver
print('Версия FPDF2:', ver)

# наследуемся от классов FPDF и HTMLMixin
# - класс FPDF для создания PDF-документа
# - класс HTMLMixin содержит парсер HTML
class HTML_PDF(FPDF, HTMLMixin):
    pass

# создаем экземпляр
pdf = HTML_PDF()
# директория где лежат системные шрифты OS Linux
font_dir = '/usr/share/fonts/truetype/freefont'
# добавляем TTF-шрифты, поддерживающие кириллицу.
# шрифт FreeSerif
pdf.add_font("Serif", style="", fname=f"{font_dir}/FreeSerif.ttf", uni=True)
pdf.add_font("Serif", style="B", fname=f"{font_dir}/FreeSerifBold.ttf", uni=True)
pdf.add_font("Serif", style="I", fname=f"{font_dir}/FreeSerifItalic.ttf", uni=True)
pdf.add_font("Serif", style="BI", fname=f"{font_dir}/FreeSerifBoldItalic.ttf", uni=True)
# шрифт FreeSans
pdf.add_font("Sans", style="", fname=f"{font_dir}/FreeSans.ttf", uni=True)
pdf.add_font("Sans", style="B", fname=f"{font_dir}/FreeSansBold.ttf", uni=True)
pdf.add_font("Sans", style="I", fname=f"{font_dir}/FreeSansOblique.ttf", uni=True)
pdf.add_font("Sans", style="BI", fname=f"{font_dir}/FreeSansBoldOblique.ttf", uni=True)
# устанавливаем шрифт по умолчанию
pdf.set_font("Serif", size=13)
# добавляем страницу
pdf.add_page()
# печатаем HTML
pdf.write_html("""
  <h1>Название документа</h1>
    <h2>Название раздела</h2>
    <p><u>Добро</u> <i>пожаловать</i> в сторонний <b>модуль FPDF2</b>.</p>
    <p><a href="https://docs-python.ru">Справочник Python3.</a></p>
    <p align="right">Это текст, выровненный по правому краю</p>
    <p>Это параграф <br>состоящий из 2-х частей без атрибута "align" (имеет перенос строки "br").</p>
    <p align="center">Это параграф, состоящий из 2-х частей 
    и имеющий атрибут "align" и не имеет переноса строки "br").</p>
    <p>Это <font color="green">зеленый</font> цвет (color="green")</p>
    <p>Это цвет <font color="#00ff00">color="#00ff00"</font></p>
    <p>Это шрифт размером <font size="9">9 пунктов (size="9")</font></p>
    <p><font face="Sans">Это подключенный шрифт FreeSans (face="Sans")</font></p>
    <h2>Другое название раздела</h2>
    <ul><li>неупорядоченные</li><li>элементы</li><li>списка</li></ul>
    <ol><li>пронумерованные</li><li>элементы</li><li>списка</li></ol>
    <br>
    <blockquote>Это цитата из HTML-блока "blockquote"</blockquote>
    <p>Выводим таблицу:</p>
    <table border="1">
      <thead>
        <tr bgcolor="silver">
          <th width="15">ID</th><th width="45">Имя</th>
        </tr>
      </thead>
      <tbody>
        <tr><td>1</td><td>Алиса</td></tr>
        <tr><td>2</td><td>Боб</td></tr>
      </tbody>
      <tfoot><tr></tr></tfoot>
    </table>
    <center>Выводим таблицу с центрированием по середине.
    Таблица занимает 60% от ширины листа:</center>
    <table border="1" width="60%">
      <thead>
        <tr bgcolor="yellow">
          <th width="20%">ID</th><th width="80%">Имя</th>
        </tr>
      </thead>
      <tbody>
        <tr><td>1</td><td>Алиса</td></tr>
        <tr><td>2</td><td>Боб</td></tr>
      </tbody>
      <tfoot><tr></tr></tfoot>
    </table>
    """, ul_bullet_char='-', table_line_separators=True)
pdf.output("html.pdf")

Описание метода FPDF.write_html()

Метод FPDF.write_html() разбирает HTML и преобразует его в PDF-документ.

Синтаксис:

pdf.write_html(html_text, image_map=None, li_tag_indent=5, 
               table_line_separators=False, ul_bullet_char='\x95', 
               heading_sizes=None)

Описание аргументов:

  • html_text: HTML-разметка, которую нужно добавить в PDF-документ;
  • image_map=None: необязательная функция с одним аргументом, которая сопоставляет src с URL-адресами новых изображений;
  • li_tag_indent=5: отступ от символа элемента списка <li>;
  • table_line_separators=False: включает/отключает разделители горизонтальных линий в таблице;
  • ul_bullet_char='\x95': символ для элемента списка <li>;
  • heading_sizes=None: