Skip to content

Підручник

Повна документація методів: fpdf.FPDF – документація API

Туторіал 1 — Мінімальний приклад

Почнемо з класичного прикладу:

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.set_font("helvetica", style="B", size=16)
pdf.cell(40, 10, "Hello World!")
pdf.output("tuto1.pdf")

Отриманий PDF

Після підключення бібліотеки ми створюємо об’єкт FPDF. Конструктор FPDF тут використовується зі значеннями за замовчуванням: сторінки формату A4, орієнтація — книжкова (portrait), одиниця виміру — міліметри. Це можна було б задати явно так:

pdf = FPDF(orientation="P", unit="mm", format="A4")

Можна встановити альбомну орієнтацію сторінки (L) або використати інші формати сторінок (наприклад, Letter і Legal) та одиниці виміру (pt, cm, in).

Поки що сторінок немає, тож треба додати одну за допомогою add_page. Початок координат — у верхньому лівому куті, поточна позиція за замовчуванням розміщена на відстані 1 см від країв; поля можна змінити за допомогою set_margins.

Перш ніж друкувати текст, обов’язково потрібно обрати шрифт за допомогою set_font, інакше документ буде некоректним. Обираємо Helvetica напівжирний розміру 16:

pdf.set_font('Helvetica', style='B', size=16)

Можна було б вказати курсив через I, підкреслення — через U, або звичайний шрифт — порожнім рядком (або будь-якою комбінацією). Зверніть увагу, що розмір шрифту задається в пунктах, а не в міліметрах (чи інших одиницях користувача); це єдиний виняток. Інші вбудовані шрифти: Times, Courier, Symbol та ZapfDingbats.

Тепер можемо вивести «комірку» за допомогою cell. Комірка — це прямокутна область, за потреби з рамкою, що містить текст. Вона рендериться у поточній позиції. Ми задаємо її розміри, текст (вирівняний по центру або інакше), чи потрібно малювати рамку, а також куди має зміститися поточна позиція після виведення (праворуч, вниз або на початок наступного рядка). Щоб додати рамку, зробимо так:

pdf.cell(40, 10, 'Hello World!', 1)

Щоб додати поруч нову комірку з текстом, вирівняним по центру, і перейти на новий рядок, зробимо так:

pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C')

Примітка: розрив рядка також можна зробити методом ln. Цей метод додатково дозволяє вказати висоту розриву.

Нарешті, документ закривається й зберігається за вказаним шляхом файлу за допомогою output. Якщо параметри не передано, output() повертає PDF як буфер bytearray.

Туторіал 2 — Колонтитули, розрив сторінки та зображення

Ось приклад на дві сторінки з верхнім/нижнім колонтитулами та логотипом:

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        # Rendering logo:
        self.image("../docs/fpdf2-logo.png", 10, 8, 33)
        # Setting font: helvetica bold 15
        self.set_font("helvetica", style="B", size=15)
        # Moving cursor to the right:
        self.cell(80)
        # Printing title:
        self.cell(30, 10, "Title", border=1, align="C")
        # Performing a line break:
        self.ln(20)

    def footer(self):
        # Position cursor at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", style="I", size=8)
        # Printing page number:
        self.cell(0, 10, f"Page {self.page_no()}/{{nb}}", align="C")


# Instantiation of inherited class
pdf = PDF()
pdf.add_page()
pdf.set_font("Times", size=12)
for i in range(1, 41):
    pdf.cell(0, 10, f"Printing line number {i}", new_x="LMARGIN", new_y="NEXT")
pdf.output("new-tuto2.pdf")

Отриманий PDF

У цьому прикладі використовуються методи header і footer для обробки колонтитулів. Вони викликаються автоматично. Ці методи вже є в класі FPDF, але нічого не роблять, тому ми розширюємо клас і перевизначаємо їх.

Логотип виводиться методом image із зазначенням його координат верхнього лівого кута та ширини. Висота обчислюється автоматично, щоб зберегти пропорції зображення.

Щоб вивести номер сторінки, ширину комірки задаємо нульовою. Це означає, що комірка розширюється до правого поля сторінки; це зручно для центрування тексту. Поточний номер сторінки повертає метод page_no; а загальну кількість сторінок отримують за допомогою спеціального значення {nb}, яке буде підставлене під час закриття документа (це значення можна змінити методом alias_nb_pages()). Зверніть увагу на використання методу set_y, який дозволяє встановити позицію в абсолютному місці на сторінці — від верху або віднизу.

Тут також використано цікаву можливість: автоматичні розриви сторінки. Щойно комірка переходить через межу сторінки (стандартно за 2 сантиметри від низу), виконується розрив, а шрифт відновлюється. Хоча в колонтитулах обрано власний шрифт (helvetica), основний текст продовжується зі шрифтом Times. Цей механізм автоматичного відновлення також стосується кольорів і товщини ліній. Межу, що ініціює розриви сторінок, задають методом set_auto_page_break.

Туторіал 3 — Розриви рядків і кольори

Продовжимо прикладом, що друкує вирівняні по ширині абзаци. Він також демонструє роботу з кольорами.

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        # Setting font: helvetica bold 15
        self.set_font("helvetica", style="B", size=15)
        # Calculating width of title and setting cursor position:
        width = self.get_string_width(self.title) + 6
        self.set_x((210 - width) / 2)
        # Setting colors for frame, background and text:
        self.set_draw_color(0, 80, 180)
        self.set_fill_color(230, 230, 0)
        self.set_text_color(220, 50, 50)
        # Setting thickness of the frame (1 mm)
        self.set_line_width(1)
        # Printing title:
        self.cell(
            width,
            9,
            self.title,
            border=1,
            new_x="LMARGIN",
            new_y="NEXT",
            align="C",
            fill=True,
        )
        # Performing a line break:
        self.ln(10)

    def footer(self):
        # Setting position at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", style="I", size=8)
        # Setting text color to gray:
        self.set_text_color(128)
        # Printing page number
        self.cell(0, 10, f"Page {self.page_no()}", align="C")

    def chapter_title(self, num, label):
        # Setting font: helvetica 12
        self.set_font("helvetica", size=12)
        # Setting background color
        self.set_fill_color(200, 220, 255)
        # Printing chapter name:
        self.cell(
            0,
            6,
            f"Chapter {num} : {label}",
            new_x="LMARGIN",
            new_y="NEXT",
            align="L",
            fill=True,
        )
        # Performing a line break:
        self.ln(4)

    def chapter_body(self, filepath):
        # Reading text file:
        with open(filepath, "rb") as fh:
            txt = fh.read().decode("latin-1")
        # Setting font: Times 12
        self.set_font("Times", size=12)
        # Printing justified text:
        self.multi_cell(0, 5, txt)
        # Performing a line break:
        self.ln()
        # Final mention in italics:
        self.set_font(style="I")
        self.cell(0, 5, "(end of excerpt)")

    def print_chapter(self, num, title, filepath):
        self.add_page()
        self.chapter_title(num, title)
        self.chapter_body(filepath)


pdf = PDF()
pdf.set_title("20000 Leagues Under the Seas")
pdf.set_author("Jules Verne")
pdf.print_chapter(1, "A RUNAWAY REEF", "20k_c1.txt")
pdf.print_chapter(2, "THE PROS AND CONS", "20k_c1.txt")
pdf.output("tuto3.pdf")

Отриманий PDF

Текст Жюля Верна

Метод get_string_width дозволяє визначити довжину рядка в поточному шрифті — тут це використовується, щоб розрахувати позицію й ширину рамки навколо заголовка. Далі встановлюємо кольори (через set_draw_color, set_fill_color і set_text_color) та товщину лінії 1 мм (проти 0,2 за замовчуванням) за допомогою set_line_width. Нарешті, виводимо комірку (останній параметр, встановлений у True, означає, що тло треба зафарбувати).

Для друку абзаців використовується метод multi_cell. Текст за замовчуванням вирівнюється по ширині. Кожного разу, коли рядок сягає правої межі комірки або зустрічається символ переведення рядка (\n), виконується розрив рядка, і автоматично створюється нова комірка під поточною. Автоматичний розрив відбувається в позиції найближчого пробілу або «м’якого переносу» (\u00ad) перед правою межею. Під час переносу рядка «м’який перенос» буде замінено на звичайний дефіс; інакше він ігнорується.

Задаються дві властивості документа: заголовок (set_title) та автор (set_author). Переглянути властивості можна двома способами. Перший — відкрити документ у Acrobat Reader, перейти в меню File і обрати Document Properties. Другий — доступний також із плагіна: натиснути правою кнопкою та вибрати Document Properties.

Туторіал 4 — Декілька колонок

Цей приклад — варіант попереднього, демонструє, як розмістити текст у кількох колонках.

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        self.set_font("helvetica", style="B", size=15)
        width = self.get_string_width(self.title) + 6
        self.set_x((210 - width) / 2)
        self.set_draw_color(0, 80, 180)
        self.set_fill_color(230, 230, 0)
        self.set_text_color(220, 50, 50)
        self.set_line_width(1)
        self.cell(
            width,
            9,
            self.title,
            border=1,
            new_x="LMARGIN",
            new_y="NEXT",
            align="C",
            fill=True,
        )
        self.ln(10)

    def footer(self):
        self.set_y(-15)
        self.set_font("helvetica", style="I", size=8)
        self.set_text_color(128)
        self.cell(0, 10, f"Page {self.page_no()}", align="C")

    def chapter_title(self, num, label):
        self.set_font("helvetica", size=12)
        self.set_fill_color(200, 220, 255)
        self.cell(
            0,
            6,
            f"Chapter {num} : {label}",
            new_x="LMARGIN",
            new_y="NEXT",
            border="L",
            fill=True,
        )
        self.ln(4)

    def chapter_body(self, fname):
        # Reading text file:
        with open(fname, "rb") as fh:
            txt = fh.read().decode("latin-1")
        with self.text_columns(
            ncols=3, gutter=5, text_align="J", line_height=1.19
        ) as cols:
            # Setting font: Times 12
            self.set_font("Times", size=12)
            cols.write(txt)
            cols.ln()
            # Final mention in italics:
            self.set_font(style="I")
            cols.write("(end of excerpt)")

    def print_chapter(self, num, title, fname):
        self.add_page()
        self.chapter_title(num, title)
        self.chapter_body(fname)


pdf = PDF()
pdf.set_title("20000 Leagues Under the Seas")
pdf.set_author("Jules Verne")
pdf.print_chapter(1, "A RUNAWAY REEF", "20k_c1.txt")
pdf.print_chapter(2, "THE PROS AND CONS", "20k_c1.txt")
pdf.output("tuto4.pdf")

Отриманий PDF

Текст Жюля Верна

Ключова відмінність від попереднього туторіалу — використання методу text_columns. Він збирає весь текст (можливо, по частинах) і розподіляє його на вказану кількість колонок, автоматично вставляючи розриви сторінок за потреби. Зверніть увагу: доки екземпляр TextColumns активний як контекстний менеджер, стилі тексту та інші властивості шрифтів можна змінювати — ці зміни будуть обмежені цим контекстом. Після його закриття попередні параметри буде відновлено.

Туторіал 5 — Створення таблиць

У цьому туторіалі пояснюється, як створити дві різні таблиці, щоб продемонструвати, чого можна досягти простими налаштуваннями.

import csv
from fpdf import FPDF
from fpdf.fonts import FontFace
from fpdf.enums import TableCellFillMode


with open("countries.txt", encoding="utf8") as csv_file:
    data = list(csv.reader(csv_file, delimiter=","))

pdf = FPDF()
pdf.set_font("helvetica", size=14)

# Basic table:
pdf.add_page()
with pdf.table() as table:
    for data_row in data:
        row = table.row()
        for datum in data_row:
            row.cell(datum)

# Styled table:
pdf.add_page()
pdf.set_draw_color(255, 0, 0)
pdf.set_line_width(0.3)
headings_style = FontFace(emphasis="BOLD", color=255, fill_color=(255, 100, 0))
with pdf.table(
    borders_layout="NO_HORIZONTAL_LINES",
    cell_fill_color=(224, 235, 255),
    cell_fill_mode=TableCellFillMode.ROWS,
    col_widths=(42, 39, 35, 42),
    headings_style=headings_style,
    line_height=6,
    text_align=("LEFT", "CENTER", "RIGHT", "RIGHT"),
    width=160,
) as table:
    for data_row in data:
        row = table.row()
        for datum in data_row:
            row.cell(datum)

pdf.output("tuto5.pdf")

Отриманий PDFCSV-дані про країни

Перший приклад реалізовано максимально простим способом — передаючи дані в FPDF.table(). Результат елементарний, але отримується дуже швидко.

Друга таблиця містить покращення: кольори, обмежену ширину таблиці, зменшену висоту рядків, вирівнювання заголовків по центру, колонки з користувацькими ширинами, вирівнювання чисел праворуч... Крім того, горизонтальні лінії прибрано. Цього досягнуто вибором значення borders_layout з-поміж доступних у TableBordersLayout.

Туторіал 6 — Створення посилань і змішування стилів тексту

У цьому туторіалі показано кілька способів вставки посилань у PDF-документ, а також додавання посилань на зовнішні ресурси.

Також буде показано кілька способів використання різних стилів тексту (напівжирний, курсив, підкреслений) в одному фрагменті.

from fpdf import FPDF


pdf = FPDF()

# First page:
pdf.add_page()
pdf.set_font("helvetica", size=20)
pdf.write(5, "To find out what's new in self tutorial, click ")
pdf.set_font(style="U")
link = pdf.add_link(page=2)
pdf.write(5, "here", link)
pdf.set_font()

# Second page:
pdf.add_page()
pdf.image(
    "../docs/fpdf2-logo.png", 10, 10, 50, 0, "", "https://py-pdf.github.io/fpdf2/"
)
pdf.set_left_margin(60)
pdf.set_font_size(18)
pdf.write_html(
    """You can print text mixing different styles using HTML tags: <b>bold</b>, <i>italic</i>,
<u>underlined</u>, or <b><i><u>all at once</u></i></b>!
<br><br>You can also insert links on text, such as <a href="https://py-pdf.github.io/fpdf2/">https://py-pdf.github.io/fpdf2/</a>,
or on an image: the logo is clickable!"""
)
pdf.output("tuto6.pdf")

Отриманий PDFfpdf2-logo

Новий метод, що використовується тут для виведення тексту, — write(). Він дуже схожий на multi_cell(), але з такими ключовими відмінностями:

  • Кінець рядка — на правому полі, а наступний рядок починається від лівого поля.
  • Поточна позиція зміщується в кінець виведеного тексту.

Тож метод дозволяє написати фрагмент тексту, змінити стиль шрифту і продовжити з того самого місця. З іншого боку, головний недолік полягає в тому, що не можна вирівняти текст по ширині, як це робить метод multi_cell().

На першій сторінці прикладу ми використали write() саме з цією метою. Початок речення надруковано звичайним стилем, потім за допомогою set_font() перемкнулися на підкреслення і завершили речення.

Щоб додати внутрішнє посилання на другу сторінку, ми використали метод add_link(), який створює клікабельну область (ми назвали її «link»), що веде на іншу сторінку документа.

Щоб створити зовнішнє посилання за допомогою зображення, ми використали image(). Цей метод має параметр для передавання посилання. Посилання може бути як внутрішнім, так і зовнішнім.

Як альтернативу, для зміни стилю шрифту та додавання посилань можна використати метод write_html(). Це HTML-розбірник, що дозволяє додавати текст, змінювати стиль шрифту та додавати посилання за допомогою HTML.

Туторіал 7 — Створення документів PDF/A

Нове у 2.8.3

Стандарти PDF/A

PDF/A-1 використовує PDF-версію 1.4. Усі ресурси (зображення, графіка, шрифти) мають бути вбудовані в документ. Керування кольорами має бути точним і платформонезалежним, із зазначенням профілів ICC, а метадані документа мають бути надані у вигляді XMP-метаданих.

PDF/A-2 використовує PDF-версію 1.7. Дозволяє стиснення JPEG2000, прозорі елементи, шрифти OpenType та цифрові підписи.

Єдине розширення для PDF/A-3 — можливість вбудовувати будь-які файли.

Класи відповідності

Рівень A (accessible, «доступний») охоплює всі вимоги стандарту, зокрема відображення структурованого змісту та правильний порядок читання вмісту документа. Текст має бути витягуваним, а структура — відображати природну послідовність читання.

Рівень B (Basic, «базовий») гарантує чітке візуальне відтворення вмісту. Рівень B зазвичай легше згенерувати, ніж рівень A, але він не забезпечує 100-відсоткового вилучення тексту чи можливості пошуку. Безпроблемне повторне використання вмісту не обов’язково гарантоване.

Щоб цього досягти, ось невеликий приклад:

from pathlib import Path

from fpdf import FPDF
from fpdf import FPDF_VERSION


DIR = Path(__file__).parent
FONT_DIR = DIR / ".." / "test" / "fonts"

pdf = FPDF(enforce_compliance="PDF/A-3B")
pdf.set_lang("en-US")
pdf.set_title("Tutorial7")
pdf.set_author(["John Dow", "Jane Dow"])
pdf.set_subject("Example for PDF/A")
pdf.set_keywords(["example", "tutorial", "fpdf", "pdf/a"])
pdf.set_producer(f"py-pdf/fpdf2 {FPDF_VERSION}")
pdf.add_font(fname=FONT_DIR / "DejaVuSans.ttf")
pdf.add_font("DejaVuSans", style="B", fname=FONT_DIR / "DejaVuSans-Bold.ttf")
pdf.add_font("DejaVuSans", style="I", fname=FONT_DIR / "DejaVuSans-Oblique.ttf")
pdf.add_page()
pdf.set_font("DejaVuSans", style="B", size=20)
pdf.write(text="Header")
pdf.ln(20)
pdf.set_font(size=12)
pdf.write(text="Example text")
pdf.ln(20)
pdf.set_font(style="I")
pdf.write(text="Example text in italics")

pdf.output("tuto7.pdf")

Отриманий PDF: tuto7.pdf

Такі інструменти, як VeraPDF, можуть перевірити відповідність створених PDF-документів:

verapdf --format text -v tutorial/tuto7.pdf

Результат:

PASS fpdf2/tutorial/tuto7.pdf 3b