В borb можно программно собирать PDF-отчёты, счета, билеты, анкеты и формы из абзацев, изображений, таблиц, списков, фигур и SmartArt, а затем читать готовые документы, извлекать из них текст, картинки и метаданные, добавлять аннотации и сохранять изменённый файл. Главные инструменты — Document и Page для структуры, PageLayout для размещения, LayoutElement для содержимого и PDF.read с PDF.write для ввода и вывода.
Рабочий процесс начинается с документа и страницы: к Page подключают SingleColumnLayout, MultiColumnLayout или точное позиционирование, после чего последовательно добавляют Paragraph, Image, Table и другие элементы. Автоматический макет следит за полями, переносит содержимое вниз и создаёт следующую страницу, когда текущей высоты уже недостаточно, поэтому типовой многостраничный документ не приходится раскладывать вручную по координатам.
Оформление задаётся в коде рядом с данными: шрифт, кегль, цвет, выравнивание, фон, рамки, скругления, отступы и размеры передаются элементам или ячейкам контейнера. Для обработки существующего PDF сначала получают объект Document, затем выбирают страницы и нужные объекты, применяют фильтры или изменения и записывают результат в новый путь; такой порядок удобен для пакетных операций и воспроизводимых шаблонов.
Скачать borb
- Редактирование PDF
- Русский интерфейс
- Просто новичкам
- Нужны навыки Python
- Нет визуального редактора
- AGPL для закрытого кода
Как устроена работа с borb
borb описывает PDF не как набор экранов редактора, а как дерево объектов. Document хранит страницы и общие свойства, Page представляет отдельный лист, а содержимое страницы формируется объектами LayoutElement. Такое разделение важно в больших проектах: бизнес-данные остаются в моделях приложения, правила оформления — в функциях построения элементов, а запись PDF выполняется в одном контролируемом месте. Если меняется шаблон счёта или отчёта, правят генератор, после чего все новые документы получают одинаковую структуру.
Минимальный сценарий включает четыре действия: создать Document, добавить Page, связать страницу с PageLayout и передать макету Paragraph. Завершающий вызов PDF.write сериализует объектную модель в файл. В этом каркасе легко заменить единственный абзац таблицей, списком или группой элементов, не меняя принцип управления документом. Путь вывода лучше формировать через pathlib.Path, заранее создавать каталог и не использовать входной файл как выходной, пока операция не проверена на копии.
from pathlib import Path
from borb.pdf import Document, Page, PageLayout, SingleColumnLayout, Paragraph, PDF
doc = Document()
page = Page()
doc.append_page(page)
layout: PageLayout = SingleColumnLayout(page)
layout.append_layout_element(Paragraph("Отчёт сформирован"))
PDF.write(what=doc, where_to=Path("output/report.pdf"))
В реальном генераторе этот код стоит обернуть в функцию, принимающую данные и путь назначения. Функция должна проверять обязательные поля до построения макета, иначе ошибка обнаружится после добавления десятков элементов. Полезно разделить генерацию на небольшие операции вроде make_header, make_items_table и make_footer: каждая возвращает LayoutElement или контейнер, а вызывающий код определяет последовательность. Такой подход позволяет тестировать отдельные блоки и повторно использовать их в счетах, актах и коммерческих предложениях.
Document, Page и PageLayout
Document отвечает за порядок страниц. Новую Page сначала создают, затем добавляют в документ, и только после этого строят её содержимое. Если страницы имеют разные роли, например титульную, основную и приложение, для каждой можно выбрать собственный макет и поля. Объекты Page не следует переиспользовать между документами: проще создать страницу заново, чтобы не переносить ссылки на ресурсы и ранее добавленный контент.
PageLayout решает задачу размещения. SingleColumnLayout ведёт единый вертикальный поток и подходит для писем, отчётов, договоров и инструкций. MultiColumnLayout делит рабочую область на несколько колонок, что удобно для бюллетеней и плотных справочных листов. Точное размещение используют, когда координаты определены бланком: билет, этикетка, сертификат или слой поверх существующей формы. Не стоит смешивать автоматический поток и множество абсолютных координат без необходимости, потому что при изменении текста блоки начинают перекрываться.
Поля задают рабочую прямоугольную область. При расчёте шаблона учитывают не только внешние отступы, но и высоту колонтитула, место под номер страницы и безопасную зону печати. Элемент, который не помещается в остаток страницы, автоматический макет переносит дальше; однако единый крупный объект, превышающий полезную высоту листа, нельзя корректно разместить простым переносом. Большую таблицу нужно разбить на строки или страницы, изображение — уменьшить, а длинный текст — передать элементу, поддерживающему перенос и усечение.

LayoutElement как общий строительный блок
Абзацы, изображения, таблицы, формы и специализированная графика наследуют общую идею LayoutElement. Благодаря этому контейнеры могут принимать разные типы содержимого, а оформление задаётся похожими параметрами: размер, фон, рамка, внутренние отступы, горизонтальное и вертикальное выравнивание. На практике это позволяет положить Paragraph и Image в соседние ячейки таблицы, поместить форму рядом с пояснением или собрать карточку товара из нескольких элементов без ручной отрисовки каждой строки.
Размеры в PDF выражаются в пунктах. При переносе макета из браузерного прототипа нельзя механически копировать пиксели: сначала определяют физический размер листа, поля и ширину колонок, затем переводят дизайн в пункты. Изображение с размером 1200×800 пикселей не обязано занимать 1200×800 пунктов; его визуальный размер задаётся отдельно, а исходное разрешение влияет на чёткость. Для печати лучше иметь запас пикселей и не растягивать небольшой файл до ширины страницы.
У каждого элемента должен быть предсказуемый контракт. Если функция возвращает таблицу, она не должна одновременно записывать PDF или менять глобальные цвета. Если оформление зависит от статуса заказа, выбирают стиль до создания ячейки и передают его явно. Так проще найти причину неожиданного фона, шрифта или отступа. Отдельный набор констант для типографики и палитры уменьшает расхождения между разделами одного документа.
Установка и проверка окружения
Для начала нужен интерпретатор Python и изолированное виртуальное окружение. В документации примеры ориентированы на Python 3, а проектные индикаторы выделяют Python 3.10–3.12; пакетные метаданные допускают более широкий диапазон. Для нового проекта разумно выбрать один из явно тестируемых современных выпусков Python, закрепить его в CI и не смешивать зависимости нескольких приложений в общей системной среде.
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux и macOS
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install borb
Базовая установка содержит ядро чтения, записи и макета. Некоторые элементы используют необязательные зависимости. Набор image добавляет Pillow, matplotlib, генераторы штрихкодов, аватаров, QR-кодов и сетевые запросы; набор text включает инструменты для шрифтов; full устанавливает все объявленные дополнения. Не следует ставить максимальный набор автоматически на сервер: лишние библиотеки увеличивают образ, время проверки и поверхность обновлений. Сначала перечисляют используемые классы и выбирают минимальный extra.
python -m pip install "borb[image]"
python -m pip install "borb[text]"
# Все дополнительные возможности
python -m pip install "borb[full]"
После установки выполняют короткий генератор с одним абзацем и проверяют три результата: модуль импортируется, каталог вывода доступен на запись, PDF открывается в двух разных просмотрщиках. Эта проба выявляет ошибки окружения раньше, чем в проект добавятся внешние шрифты и изображения. Точные выпуски зависимостей фиксируют в lock-файле или requirements-файле с хешами, а обновление сначала прогоняют на контрольном наборе документов.
На сервере важно отделить временные файлы каждого запроса. Имя назначения должно быть уникальным, а каталог — очищаться после отправки результата. При параллельной генерации нельзя всем процессам писать в output.pdf. Для фоновых заданий полезно сохранять идентификатор заказа в имени и вести журнал: начало построения, число страниц, размер результата, время записи и исключение без содержимого персональных полей.
Текст, шрифты и типографика
Paragraph — основной элемент для текста. Он принимает строку и параметры оформления, переносит слова в доступной ширине и участвует в автоматическом потоке. Для заголовков есть Heading, для единообразных фрагментов — HomogeneousParagraph, для сочетания участков с разным стилем — HeterogeneousParagraph. MarkdownParagraph удобен, когда вход уже содержит ограниченную разметку, но перед массовым использованием нужно проверить поддерживаемые конструкции и очистить пользовательский Markdown от нежелательных фрагментов.
Стандартные четырнадцать PDF-шрифтов дают компактный файл и не требуют встраивания, но они плохо подходят для русского текста и фирменной типографики. Для кириллицы выбирают TTF с нужным набором глифов и проверяют лицензию шрифта на встраивание. Один и тот же файл шрифта следует загружать централизованно и переиспользовать, а не искать его заново для каждого абзаца. Если часть символов отображается квадратами, причина обычно в отсутствии глифов, а не в кодировке строки Python.
При выборе кегля учитывают фактическую ширину полей. Длинные артикулы, адреса электронной почты и номера без пробелов могут не иметь точки переноса. Такие значения нормализуют заранее: разрешают разрыв в безопасных местах, сокращают отображаемую форму или выделяют им отдельную широкую колонку. Уменьшение кегля до нечитабельного размера должно быть последним вариантом, особенно в договорах и счетах.

Цвет текста можно задавать готовыми именованными значениями или компонентами цветовой модели. Для экранных материалов достаточно контролировать RGB, для печатного процесса макет сверяют с требованиями типографии и пробным выводом. Нельзя рассчитывать, что яркий экранный оттенок будет одинаковым на офисном принтере. Контраст проверяют не только визуально: светло-серый текст на белом фоне может исчезнуть после копирования или печати в экономичном режиме.
Выравнивание выбирают по задаче. Левое даёт стабильные интервалы и хорошо работает в интерфейсных документах, центрирование подходит коротким заголовкам, правое — числам и реквизитам, а выключка по ширине требует достаточной длины строки. В узкой колонке выравнивание по ширине создаёт большие пробелы, поэтому для много колоночного текста лучше проверить несколько абзацев с короткими словами и длинными терминами.
Фон, рамки и внутренние отступы превращают Paragraph в самостоятельный информационный блок. Отступ относится к внутреннему расстоянию между текстом и границей элемента; внешний промежуток лучше контролировать на уровне последовательности или контейнера. При скруглённых границах фон и рамка должны иметь согласованный радиус. Слишком большой радиус на низкой строке образует капсулу и уменьшает полезную ширину, поэтому его проверяют на самых коротких и самых длинных значениях.
Для повторяемой типографики создают функции вроде body_text, section_heading и warning_box. Они принимают только текст и редко меняющиеся параметры. Тогда заголовок в пятнадцати местах не расходится по кеглю или цвету после точечной правки. Если документ поддерживает несколько языков, набор шрифтов выбирают по покрытию символов, а не по имени языка: один файл может закрыть кириллицу и латиницу, но не содержать математические знаки или иероглифы.
Переполнение и усечение
Переполнение возникает, когда содержимое превышает прямоугольник, который макет может выделить. В свободном потоке абзац обычно занимает необходимую высоту, но внутри ячейки, карточки или точно позиционированной области доступное место ограничено. Перед генерацией полезно прогнать крайние данные: самое длинное имя, максимальный адрес, десятизначную сумму, многострочный комментарий и пустое значение. Тест на среднем примере не показывает проблемы макета.
Усечение допустимо только для второстепенных полей и должно быть заметно пользователю, например через многоточие. Юридический текст, условия оплаты и названия товаров обрезать нельзя. Для них выбирают перенос на следующую страницу, расширение строки таблицы или уменьшение количества соседних колонок. Если высота блока фиксирована внешним бланком, полный текст можно вынести на отдельную страницу и оставить в бланке короткую ссылочную формулировку без внешнего URL.
Изображения, QR-коды и штрихкоды
Image помещает растровый или поддерживаемый векторный материал в макет. Официальные примеры показывают работу с JPEG, PNG, GIF и SVG. Файл может быть локальным ресурсом, однако для воспроизводимого документа предпочтительнее заранее скачать и проверить ресурс, а не зависеть от сетевого адреса во время PDF.write. Локальный путь исключает задержки, недоступность сервера и неожиданную замену картинки.

Размер изображения задают в пунктах, сохраняя пропорции. Для фотографии рассчитывают вписывание в прямоугольник: коэффициент равен меньшему из отношений допустимой ширины и высоты к исходным размерам. Принудительное растяжение по двум независимым осям искажает лица, логотипы и штрихкоды. Если важна обрезка, её выполняют осознанно до вставки, оставляя исходник нетронутым.
Большие фотографии нужно уменьшать до разумного разрешения перед генерацией. Вставка десятков снимков с камеры по 20–40 мегапикселей резко увеличивает память и итоговый PDF, хотя на странице они занимают несколько сантиметров. Для экранного отчёта обычно достаточно разрешения, соответствующего отображаемому размеру; для печати выбирают плотность по требованиям печати. Сжатие проверяют на мелком тексте и тонких линиях, потому что они разрушаются раньше фотографии.
QRCode создаёт матричный код из текста. В код помещают стабильный идентификатор, короткий адрес или компактные данные; длинная строка увеличивает плотность модулей и ухудшает считывание. Вокруг кода оставляют светлую тихую зону, не накладывают фоновые узоры и не уменьшают его до размера, который камера не различает. После генерации код сканируют несколькими устройствами с экрана и с распечатки.

Класс Barcode и связанные дополнительные зависимости позволяют создавать линейные штрихкоды. Формат выбирают по стандарту бизнес-процесса, а не по внешнему виду: кассовая система, складской сканер и перевозчик могут принимать разные символогии. Контрольную цифру и допустимый алфавит проверяют до построения элемента. Подпись под кодом следует считать отдельным текстом, если её формат или язык должен отличаться от автоматического представления.
Avatar, Equation, Chart и Screenshot относятся к специализированным визуальным элементам. Часть из них требует дополнительных библиотек или внешних сервисов. Для отчётности с долгим сроком хранения лучше формировать график локально из зафиксированных данных, а не получать картинку по изменяемому сетевому запросу. Формулу проверяют на наборе символов и шрифте, а снимок страницы — на разрешении и праве использования содержимого.
Фигуры, линии и индикаторы
Shape позволяет рисовать линии, прямоугольники, окружности и многоугольники. Эти объекты полезны для разделителей, рамок, схем и простых пиктограмм, когда растровое изображение было бы лишним. Векторная фигура остаётся чёткой при масштабировании. Её оформление включает толщину и цвет контура, заливку, штрих и прозрачность; параметры следует сопоставлять с размером элемента, иначе тонкая линия исчезнет на печати, а толстая перекроет содержимое.

Координаты вершин задают геометрию. Для повторяющихся диаграмм удобнее вычислять их из ширины и высоты области, чем хранить набор случайных чисел. Тогда фигура масштабируется вместе с карточкой. Перед записью проверяют порядок точек: самопересекающийся контур может заливаться неожиданно, а незамкнутая линия не образует область.
ProgressBar и ProgressSquare визуализируют долю выполнения. Входное значение нормализуют в заранее определённый диапазон и ограничивают границами, чтобы 130 процентов не вышли за рамку. Рядом указывают числовое значение, поскольку цвет или длина полосы могут быть недостаточны для точного чтения и пользователей с нарушением цветового восприятия.
Map-подобные элементы применяют для географических или схематических представлений, но итог нужно оценивать в масштабе страницы. Мелкие подписи и границы регионов быстро становятся неразличимыми. Если карта несёт важные данные, добавляют легенду, единицы измерения и текстовый итог. Интерактивность просмотрщика не должна быть единственным способом понять документ.
Списки и контейнеры
OrderedList, UnorderedList, ABCOrderedList и RomanNumeralOrderedList организуют однотипные пункты. Элемент списка может содержать не только строку, но и другой LayoutElement, поэтому внутри пункта можно сочетать заголовок и пояснение. Для простого текста лучше оставаться на одном уровне вложенности: глубокая иерархия быстро съедает ширину и создаёт проблемы переноса.

Маркер и текст должны иметь достаточный промежуток. Двузначные номера, длинные римские обозначения и буквы после Z требуют больше места, чем первые три пункта, поэтому тестовый список должен включать максимальный индекс. Если порядок не имеет смыслового значения, используют маркированный вариант, чтобы читатель не воспринимал номера как приоритет или последовательность действий.
Контейнеры помогают собирать повторяемые карточки. Например, строку списка товаров можно представить таблицей с изображением, названием, количеством и суммой; группу карточек — вложить в более крупный контейнер. Но чрезмерное вложение усложняет расчёт размеров. Когда один и тот же эффект можно получить одной таблицей с объединением ячеек, плоская структура обычно проще для отладки.
Таблицы: фиксированная и гибкая ширина
FixedColumnWidthTable задаёт число строк и столбцов, а также при необходимости относительные ширины. Этот вариант выбирают для счетов, реквизитов и форм, где положение колонок должно оставаться одинаковым на каждой странице. FlexibleColumnWidthTable распределяет ширину по содержимому и удобна для небольших наборов данных с непредсказуемой длиной. Гибкость не отменяет проверки: одна очень длинная строка может отнять место у остальных столбцов.

Ячейки заполняются последовательно. Заданное количество строк и столбцов должно соответствовать числу добавленных элементов с учётом объединений. Ошибка в расчёте проявляется смещением данных или невозможностью построить таблицу. Практичный способ — сначала сформировать двумерную модель, проверить длину каждой строки и только затем преобразовать её в элементы. Заголовок таблицы создают явно, а не определяют по позиции случайного элемента.
TableCell поддерживает объединение по строкам и столбцам. Объединение удобно для групповых заголовков, но оно усложняет перенос таблицы через страницы. Если таблица длинная, шапку лучше держать отдельной повторяемой структурой и избегать вертикальных объединений, пересекающих потенциальную границу страницы. Для экспортных отчётов читателю важнее повтор заголовков, чем декоративная сложность.
Фон, рамки и padding задают визуальную сетку. Метод установки отступов на всех ячейках ускоряет базовую настройку, а отдельные ячейки можно выделить затем. Полное удаление рамок подходит для двухколоночных реквизитов, где таблица служит только выравнивателем. Для числовых данных правое выравнивание облегчает сравнение разрядов; десятичные значения форматируют одной функцией, чтобы разделитель и число знаков не менялись от строки к строке.
Суммы нельзя вычислять внутри визуального слоя случайными преобразованиями строк. Сначала используют Decimal и правила округления предметной области, затем передают готовое отображаемое значение. Иначе двоичная арифметика float может дать расхождение между позициями и итогом. Валюту, налог и скидку хранят отдельно, а в PDF выводят и промежуточные значения, если документ должен быть проверяемым.
Для многостраничной ведомости данные делят на порции по фактической высоте строк, а не только по их числу. Строка с длинным описанием выше обычной. Безопасный алгоритм добавляет строки до достижения лимита, завершает таблицу, создаёт следующую страницу и повторяет шапку. Если автоматический макет умеет перенести контейнер только целиком, таблицу нужно заранее разбивать на несколько контейнеров.
Интерактивные PDF-формы
FormField и производные классы создают заполняемые поля. TextField подходит для одной строки, TextArea — для многострочного комментария, CheckBox — для независимого выбора, RadioButton — для одного варианта из группы, DropDownList — для компактного перечня. CountryDropDownList и GenderDropDownList дают специализированные наборы, однако перед использованием их значения и язык нужно сверить с требованиями конкретной анкеты.

Каждому полю назначают уникальное имя. Оно служит ключом при извлечении заполненных данных, поэтому отображаемая подпись и технический идентификатор должны быть разными сущностями. Имя лучше делать стабильным и латинским, например applicant_email, а рядом выводить понятную русскую подпись. Изменение ключа после запуска формы ломает интеграцию с обработчиком ответов.
Значение по умолчанию применяют только там, где оно безопасно. Предварительно отмеченное согласие или выбранный платный вариант создают риск ошибочного подтверждения. Placeholder не заменяет подпись: после ввода подсказка исчезает, а распечатанный документ может стать непонятным. Обязательность поля также нужно проверять после получения файла, потому что разные просмотрщики по-разному подсказывают незаполненные элементы.
Button и JavascriptButton добавляют действия, но поддержка JavaScript зависит от PDF-просмотрщика и его политики безопасности. Браузерный просмотр, мобильное приложение и специализированный клиент могут вести себя по-разному или полностью игнорировать сценарий. Критическое действие, например расчёт суммы или отправка данных, нельзя оставлять только на JavaScript внутри PDF; его дублируют серверной проверкой или понятной инструкцией.
Внешний вид поля проверяют в нескольких программах. Цвет рамки, шрифт значения, стрелка списка и подсветка фокуса могут отличаться, поскольку часть оформления рисует просмотрщик. Для печати полезно открыть заполненную форму и убедиться, что введённые значения попадают в печатный слой. Если получатель должен видеть окончательный неизменяемый результат, после валидации данные можно перенести в обычные текстовые элементы и сформировать отдельную финальную копию.
Анкета пациента из официальных примеров показывает сочетание формы, рамки и точного макета. В производственном документе дополнительно нужны правила конфиденциальности: минимизировать собираемые поля, не писать значения в открытый журнал, хранить временный PDF ограниченное время и передавать его по защищённому каналу. borb формирует структуру файла, но политика доступа и срок хранения остаются задачей приложения.

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

Метод bending_process показывает процесс, который переносится на следующую строку, сохраняя стрелки между этапами. Перед генерацией определяют логический порядок и ограничивают число узлов на странице. Если этапов десятки, схему делят по фазам, а не уменьшают до нечитаемого масштаба. Цвет каждой фазы должен сопровождаться текстовой подписью, чтобы смысл не зависел только от оттенка.
Карточные представления подходят для сравнения объектов с несколькими признаками. В официальном примере отдельные блоки содержат название и маркированные свойства. Для реальных данных нужно выровнять количество текста: одна карточка с восемью строками и соседняя с двумя выглядят несбалансированно. Длинные пояснения лучше перенести под схему или в таблицу, оставив в карточке ключевые тезисы.

SmartArt не заменяет аналитический график. Если читателю нужны точные значения, рядом добавляют таблицу или подписи. Схема отвечает на вопрос о структуре и последовательности, а график — о величинах и тенденциях. При автоматизации важно выбирать вид визуализации по данным, а не использовать один шаблон для любого набора.
Шаблоны и повторяемый дизайн
Шаблоны ускоряют создание типовых документов. В примерах представлены Slideshow, A4Portrait, A4PortraitResume и A4PortraitInvoice. Они задают базовую геометрию и ожидаемую структуру, после чего приложение подставляет содержимое. Шаблон полезен, когда десятки документов должны иметь одинаковые поля, заголовки и порядок блоков; он не освобождает от проверки длинных данных и локализации.

Slideshow формирует PDF, где страницы играют роль слайдов. Текст на таком листе должен быть крупнее, чем в отчёте, а количество тезисов — меньше. График и пояснение располагают так, чтобы они читались с экрана. Анимации презентационных форматов в PDF не переносятся, поэтому последовательное раскрытие заменяют несколькими страницами или статичным итоговым состоянием.
A4Portrait задаёт распространённый портретный лист. Для печати проверяют реальные поля принтера и не размещают важные элементы вплотную к краю. Resume и Invoice дают предметную основу, но персональные данные и реквизиты должны проходить собственную валидацию. Шаблон нельзя считать юридически достаточным только из-за внешнего вида: обязательные поля зависят от страны, договора и процесса.
Собственный шаблон лучше строить как набор функций и конфигурацию стилей. В конфигурации хранят размеры страницы, поля, палитру, пути к шрифтам и параметры таблиц; в функциях — порядок элементов. Данные не должны содержать объект шрифта или цвет, если они пришли из базы. Такое разделение позволяет обновить дизайн без миграции бизнес-данных.
Практический сценарий: счёт
Счёт объединяет большинство сильных сторон borb: изображение логотипа, таблицы для реквизитов и позиций, форматирование чисел и текст условий. Генератор начинает с проверки номера, даты, валюты, продавца, покупателя и списка строк. Затем вычисляет суммы через Decimal, формирует отображаемые строки и только после этого строит PDF. Если расчёты выполнять одновременно с добавлением ячеек, тестировать налоги и скидки станет сложнее.

Верхняя часть может быть FixedColumnWidthTable из двух колонок: слева адрес и контакты, справа номер и сроки. Границы убирают, чтобы контейнер служил сеткой. Блок BILL TO и SHIP TO оформляют другой таблицей с контрастными заголовками. В строках товаров задают относительные ширины, например больше места описанию и меньше цене, количеству и итогу.
Условия оплаты располагают после таблицы или в нижней области. Слишком мелкий светло-серый шрифт выглядит аккуратно, но плохо печатается; в рабочем шаблоне кегль и контраст выбирают по требованиям чтения, а не копируют демонстрационный пример. Если условий много, их переносят на следующую страницу и оставляют явный заголовок, чтобы текст не воспринимался как случайный колонтитул.
Для партии счетов шаблон создают один раз, а генератор вызывают для каждого заказа с отдельным выходным путём. После записи проверяют, что файл существует, его размер больше минимального и количество страниц ожидаемо. Для финансово значимого процесса полезно повторно прочитать результат и убедиться, что номер и итог извлекаются как текст. Это не заменяет визуальный тест, но ловит пустые или перепутанные документы.
Практический сценарий: билет и пропуск
Билет требует точной геометрии: имя пассажира, маршрут, время, место и код проверки должны попадать в заранее определённые зоны. Автоматический поток применяют внутри отдельных блоков, а общую композицию фиксируют координатами или таблицей. До генерации нормализуют часовой пояс и формат времени, иначе два сервиса могут вывести разные даты для одного события.
QR-код или штрихкод формируют из короткого идентификатора, а не из полного набора персональных данных. Сервер по идентификатору проверяет статус билета и право доступа. Такой подход уменьшает плотность кода и объём открытой информации. Идентификатор должен быть непредсказуемым и защищённым от подбора; последовательный номер заказа сам по себе для этого не подходит.
На мобильном экране билет должен оставаться читаемым без увеличения. Код помещают на контрастном фоне, рядом оставляют номер для ручного ввода, а ключевые сведения выводят крупнее служебных. Для печати проверяют чёрно-белый режим и масштаб по размеру страницы. Если принтер уменьшает лист, тихая зона кода не должна исчезать.
Чтение и анализ существующих PDF
PDF.read загружает существующий документ в объектную модель. После этого можно работать со страницами, метаданными и содержимым. Входной файл сначала проверяют на существование и читаемость, а результат изменения записывают в другой путь. Перезапись исходника затрудняет восстановление при исключении или некорректном преобразовании.
Метаданные включают описательные поля вроде названия и автора. Они полезны для каталогизации, но не являются надёжным основанием для безопасности или юридической идентификации: пользователь может изменить их. При пакетной обработке сохраняют отдельно путь, хеш входного файла и извлечённые поля, чтобы отличить одинаковые названия документов.
Извлечение текста работает с текстовыми объектами, реально присутствующими в PDF. Страница-скан без текстового слоя вернёт мало полезного текста или ничего. В таком случае нужен OCR-компонент, после которого результат следует проверять на типичных ошибках: смешение похожих букв, потеря знаков и неправильный порядок колонок. Сам факт визуальной читаемости страницы не означает наличие извлекаемого текста.
Официальные примеры показывают фильтрацию текста по шрифту, цвету и размеру, а также поиск регулярными выражениями. Эти признаки позволяют отделить заголовки, примечания или выделенные значения, если шаблон стабилен. Для документов разного происхождения полагаться только на размер шрифта рискованно: визуально одинаковые заголовки могут иметь разные внутренние параметры. Надёжнее сочетать несколько признаков и проверять контекст.
Регулярное выражение ищет структуру, например номер договора или дату, но не подтверждает смысл. После совпадения проверяют соседние слова, допустимый диапазон и контрольную сумму, если она предусмотрена форматом. При работе с русским текстом учитывают неразрывные пробелы, разные тире и переносы строк. Предварительная нормализация должна сохранять исходное значение для аудита.
Извлечение изображений возвращает встроенные растровые ресурсы. Одна картинка может использоваться несколько раз или храниться с маской прозрачности, поэтому число ресурсов не всегда равно числу видимых иллюстраций. Файлам назначают уникальные имена, записывают страницу и область появления, а дубликаты сравнивают по хешу. Не следует автоматически публиковать извлечённые материалы без проверки прав и персональных данных.
Пример с TF-IDF показывает получение ключевых слов, а GraphML — представление структуры для дальнейшего анализа. Такие результаты зависят от качества извлечённого текста и порядка элементов. Перед аналитикой удаляют повторяющиеся колонтитулы, нормализуют регистр и отделяют страницы без содержимого. Иначе наиболее частыми ключевыми словами станут название компании и номер страницы.
Разделение и объединение документов выполняют на уровне страниц. Перед слиянием приводят порядок файлов к явному списку и проверяют ориентацию листов. После операции сравнивают число страниц с суммой исходных, открывают первую и последнюю страницу каждого фрагмента и убеждаются, что закладки или формы не получили конфликтующие имена. Для разделения сохраняют устойчивую схему именования, иначе части трудно собрать обратно.
Аннотации и изменения содержимого
Аннотации добавляют заметки и ссылки поверх страницы. Координаты нужно вычислять в системе PDF, учитывая начало отсчёта и поворот страницы. Если область получена из визуального интерфейса с началом в левом верхнем углу, преобразование выполняют в одной функции и тестируют на углах. Ошибка знака или высоты переносит аннотацию в противоположную часть листа.
Ссылка должна иметь понятную видимую подпись и достаточно большую активную область. Поскольку публичный HTML статьи не содержит внешних адресов, это правило относится к создаваемым пользователем PDF: перед вставкой URL проверяют схему и запрещают опасные варианты. Автоматически превращать любую строку из входных данных в активную ссылку нельзя.
Добавление текста и изображений к существующей странице похоже на штампование. Для штампа создают неизменяемый блок с датой, статусом или идентификатором и размещают его в зоне, где нет важных данных. На документах с разными размерами страниц координаты рассчитывают относительно ширины и высоты, а не используют одно абсолютное значение для всех файлов.
Удаление визуального объекта не всегда означает удаление информации из файла. Закрашивание прямоугольником оставляет исходный текст под ним и не является редактированием конфиденциальных данных. Для настоящего удаления используют специализированную операцию redaction, проверяют сохранённый файл повторным извлечением и ищут исходную строку в бинарном содержимом и текстовом слое. В экосистеме borb редактирование вынесено в отдельный компонент, поэтому его наличие и лицензию проверяют отдельно.
OCR, Markdown и другие дополнительные компоненты
OCR нужен для сканов и фотографий страниц. Он распознаёт изображение и добавляет или возвращает текст, но качество зависит от разрешения, наклона, языка и контраста. Перед распознаванием выравнивают страницу, удаляют большие поля и выбирают языковую модель. После распознавания сравнивают выборку с оригиналом, особенно числа, фамилии и обозначения единиц.
Компонент borb_ocr не следует путать с базовыми классами чтения PDF. Его подключают отдельно и учитывают собственные зависимости. В рабочем конвейере этапы разделяют: чтение страницы, рендер или получение изображения, OCR, нормализация текста, проверка и сохранение. Так можно повторить только неудачный этап, не создавая документ заново.
borb_markdown_to_pdf преобразует Markdown в PDF. Это удобно для документации и автоматически сформированных заметок, но результат зависит от поддерживаемой разметки и стилей. Перед импортом пользовательский Markdown очищают, ограничивают внешние ресурсы и тестируют таблицы, кодовые блоки, длинные ссылки и изображения. Для сложного фирменного макета прямое построение LayoutElement даёт больше контроля.
borb_redact предназначен для удаления конфиденциального содержимого. Важный критерий — не внешний чёрный прямоугольник, а отсутствие исходных данных после записи. Контроль включает извлечение текста, поиск строк, проверку вложений и визуальный рендер. Если документ содержит подпись, изменение может сделать её недействительной; это нужно учитывать до обработки, а не после отправки.
Дополнительные компоненты могут иметь отдельные условия использования и зависимости. Нельзя считать, что установка borb автоматически открывает OCR, редактирование и Markdown-конвертацию. В проектной документации фиксируют точное имя установленного пакета, его назначение и тестовый пример, чтобы сопровождение не зависело от памяти одного разработчика.
Совместимость файлов и просмотрщиков
Основной формат ввода и вывода — PDF. Растровые и векторные изображения используются как ресурсы внутри документа, а не превращают библиотеку в универсальный конвертер любых офисных форматов. DOCX, XLSX или презентацию сначала обрабатывают инструментом их собственного формата либо извлекают структурированные данные, после чего строят PDF. Попытка читать произвольный файл через PDF.read должна завершаться проверяемой ошибкой, а не молчаливым пустым документом.
PDF-просмотрщики различаются. Статический текст, изображения и простые векторные фигуры обычно воспроизводятся предсказуемее, чем JavaScript, сложные формы и редкие графические эффекты. Контрольный набор открывают хотя бы в браузере, системном просмотрщике и программе, которой пользуется получатель. Для печати добавляют тест на реальном принтере или стабильном виртуальном драйвере.
Поворот страницы влияет на координаты и восприятие ширины с высотой. Перед добавлением штампа или аннотации определяют медиабокс, кропбокс и поворот. Нельзя считать все страницы A4: договор может содержать приложение A3, чек узкого формата и отсканированное письмо нестандартного размера. Относительные координаты и проверка границ делают обработку устойчивее.
Встроенный шрифт повышает переносимость, но увеличивает файл. Подмножество шрифта экономит место, если документ использует ограниченный набор символов. При генерации шаблонов с меняющимися языками контрольная выборка должна содержать все алфавиты, знаки валют и математические символы, иначе проблема проявится только у отдельного клиента.
Прозрачность, градиенты и эффекты проверяют после растрирования страницы. Если PDF предназначен для стандарта долговременного хранения или типографии, требования к цветовому профилю, шрифтам и интерактивности задаются отдельно; обычная успешная запись не подтверждает соответствие специализированному стандарту. Для таких задач нужен валидатор и профильный тестовый процесс.
Производительность и пакетная генерация
Скорость зависит от числа страниц, количества элементов, размеров изображений и сложности шрифтов. Сначала измеряют базовый документ, затем добавляют реальные ресурсы и находят узкое место. Оптимизация без измерений часто направлена не туда: например, цикл по строкам может быть быстрым, а основное время уйдёт на загрузку сетевых картинок или создание графиков.
Изображения кэшируют по хешу или устойчивому идентификатору. Если один логотип используется на каждой странице, его не нужно повторно читать с диска и преобразовывать для каждого элемента. Однако кэш должен иметь ограничение размера и очищаться между независимыми наборами, иначе долгоживущий процесс накопит память. Персональные изображения нельзя хранить в общем кэше без политики удаления.
Большой документ делят на логические части, если это допускает процесс. Сначала можно сформировать главы или приложения, затем объединить их в заданном порядке. Такой подход упрощает повторную генерацию неудачного фрагмента, но требует проверить общую нумерацию, закладки и формы. Имена полей формы в разных частях должны быть уникальными, иначе просмотрщик может связать их значения.
Параллельность применяют на уровне независимых документов, а не совместной записи одного файла несколькими процессами. Рабочий процесс получает собственный каталог, входные данные и имя результата. Число процессов ограничивают памятью: несколько задач с большими изображениями могут исчерпать её быстрее, чем загрузить процессор. Метрики должны включать пиковое потребление памяти, а не только время.
Для повторяемости фиксируют зависимости и шрифты. Обновление шрифтов может изменить перенос строк и число страниц даже при том же коде. Контрольные PDF сравнивают не только по бинарному хешу, потому что метаданные и внутренний порядок объектов могут отличаться; полезнее растрировать страницы и сравнивать изображения с допустимым порогом, а также извлекать ключевые строки и координаты.
Логи не должны содержать полный текст документа. Достаточно идентификатора задания, количества страниц, размеров ресурсов, времени этапов и типа исключения. При ошибке пользовательского поля записывают имя поля и категорию проблемы, но не значение, если оно персональное. Это особенно важно для анкет, медицинских документов и финансовых отчётов.
Надёжность и проверка результата
Успешный вызов PDF.write означает, что файл записан, но не гарантирует правильность содержания. Автоматическая проверка должна открыть результат, сравнить количество страниц, наличие обязательных фраз и метаданных, а при необходимости извлечь итоговые суммы. Визуальная проверка контрольных примеров остаётся обязательной для макета: текст может существовать, но быть белым, перекрытым или вынесенным за границу.
Для регрессионных тестов готовят небольшой набор данных: пустые необязательные поля, максимальные строки, один и много товаров, отрицательная скидка, разные валюты, кириллица и смешанный алфавит. Каждый пример имеет ожидаемое число страниц и ключевые значения. После изменения шаблона тесты показывают, где поменялся перенос или пропал элемент.
Файлы от пользователей считаются недоверенными. Ограничивают размер, число страниц и время обработки, используют отдельный рабочий каталог и не следуют произвольным внешним ссылкам из документа. Если обработка выполняется в сервисе, процесс запускают с минимальными правами и без доступа к секретам приложения. Проверка расширения недостаточна: файл должен иметь сигнатуру PDF и успешно разбираться.
При исключении временный файл удаляют или помечают как неполный. Нельзя отдавать пользователю результат, созданный до ошибки на середине документа. Безопасная схема пишет во временное имя, выполняет проверки и только затем атомарно переносит файл в окончательное место. Это также предотвращает чтение результата другим процессом до завершения записи.
Цифровая подпись PDF требует отдельного процесса. Любое добавление текста, формы или метаданных после подписания может нарушить проверку подписи. Поэтому сначала выполняют все преобразования, затем валидируют документ и только после этого подписывают подходящим инструментом. При обработке уже подписанного файла приложение должно предупреждать о последствиях до изменения.
Типовые ошибки и способы устранения
Модуль не импортируется
Ошибка ModuleNotFoundError обычно означает, что пакет установлен не в тот интерпретатор. Проверяют путь командой python -c с выводом sys.executable, затем запускают установку через python -m pip из того же окружения. В IDE выбирают именно .venv проекта. Если импортируется другой пакет с похожим именем, просматривают путь модуля и удаляют конфликтующий локальный файл borb.py.
Не найден класс или дополнительная зависимость
Если импорт отдельного элемента завершается ошибкой, сначала сверяют имя и модуль с документацией установленного пакета. Для Image, Chart, QRCode и других специализированных элементов может требоваться extra. Устанавливают минимальный нужный набор и перезапускают интерпретатор. Нельзя исправлять проблему копированием случайного импорта из старого примера без проверки, потому что структура API и перечень зависимостей могут различаться.
Русские буквы заменяются квадратами
Причина почти всегда в шрифте без кириллицы или неверно выбранном начертании. Открывают TTF в просмотрщике шрифтов, проверяют нужные символы и передают этот файл Paragraph. Затем создают тестовую строку с русскими буквами, цифрами, знаком рубля, тире и кавычками. Если обычное начертание работает, а жирное нет, для жирного нужно отдельное TTF, а не только программный флаг.
Элемент не помещается на страницу
Сначала измеряют доступную область после полей и предыдущих элементов. Изображение уменьшают с сохранением пропорций, таблицу делят на части, а текст разрешают переносить. Если проблема возникает только на одном наборе данных, находят самое длинное поле. Точное размещение требует ручной проверки пересечений; автоматический SingleColumnLayout лучше подходит для неизвестной высоты текста.
Таблица съезжает или не заполняется
Проверяют number_of_rows, number_of_columns и число добавленных элементов с учётом row_span и column_span. Затем временно включают контрастные рамки всех ячеек и выводят короткие метки с индексами. После исправления структуру возвращают к рабочему стилю. Данные формируют по строкам одной длины, а пропущенные значения заменяют пустым Paragraph, чтобы последовательность не смещалась.
PDF слишком большой
Сначала считают суммарный размер исходных изображений. Фотографии уменьшают до отображаемого разрешения и выбирают подходящее сжатие. Проверяют, не вставляется ли один логотип в нескольких вариантах и не встраиваются ли полные крупные шрифты для нескольких начертаний. Затем сравнивают размер после каждого класса ресурсов; бессистемное сжатие всего документа может ухудшить текст и коды.
Форма работает не во всех просмотрщиках
Открывают файл в целевых клиентах и отделяют статическое отображение от действий JavaScript. Поля формы должны иметь уникальные имена и видимые подписи. Критические расчёты выполняют вне PDF, а результат записывают как обычный текст. Для получателя, который использует браузер, готовят инструкцию или плоскую копию, если интерактивность не обязательна.
Из PDF не извлекается текст
Проверяют, можно ли выделить текст мышью в просмотрщике. Если страница является изображением, запускают OCR. Если текст есть, но порядок странный, анализируют колонки, поворот и координаты; простой линейный вывод может смешать соседние блоки. Фильтры по шрифту и размеру применяют после базового извлечения, иначе слишком строгий критерий вернёт пустой результат.
Результат повреждён после изменения
Никогда не пишут поверх единственной исходной копии. Сохраняют в новый файл, проверяют его повторным PDF.read и открывают несколько страниц. Если ошибка связана с конкретным входом, уменьшают операцию до одного действия и одной страницы, сохраняя хеш исходника. Это помогает отличить проблему структуры PDF от ошибки шаблона.
Лицензирование и внедрение
borb распространяется по двойной модели: AGPL и коммерческая лицензия. Для учебного, исследовательского или открытого проекта условия AGPL могут быть приемлемы, но команда должна прочитать текст лицензии и выполнить его требования. Закрытый код, платный PDF-сервис и распространение в составе закрытого продукта производитель прямо относит к сценариям, для которых предлагается коммерческая лицензия.
Лицензионное решение принимают до интеграции в архитектуру. В реестре зависимостей фиксируют название пакета, лицензию, выбранное основание использования и владельца решения. Если проект распространяется клиентам или работает как сетевой сервис, юридическая оценка особенно важна. Техническая возможность установить пакет не равна праву использовать его в любой модели.
Дополнительные шрифты, изображения и данные имеют собственные права. Встраивание фирменного шрифта требует разрешения, стоковая фотография может запрещать перераспределение, а карта — требовать атрибуцию. Генератор должен использовать только утверждённые ресурсы из контролируемого каталога. Сетевой поиск случайной картинки во время формирования отчёта создаёт и правовой, и технический риск.
При закупке коммерческой лицензии отдельно уточняют число разработчиков, среду развертывания, использование в облаке и порядок обновлений. Эти условия не следует угадывать по названию тарифа. Документ с решением хранят рядом с архитектурной документацией, а не внутри исходного кода с персональными контактами.
Сравнение borb с аналогами
| Программа | Лучше подходит для | Главное ограничение |
|---|---|---|
| borb | Генерация и обработка PDF в одном Python API | Нужен код и учёт лицензии AGPL |
| PDF Commander | Ручное визуальное редактирование страниц и текста | Не предназначен для серверной автоматизации |
| pypdf | Слияние, разделение, поворот и изменение существующих PDF | Нет высокоуровневого поточного макета |
| PyMuPDF | Быстрый рендер, извлечение и координатные изменения | Сложный документ чаще размещают по координатам |
| ReportLab | Создание отчётов, типографики и графиков | Чтение и изменение готовых PDF не основной сценарий |
| pdfplumber | Извлечение текста, таблиц и визуальная отладка | Не создаёт полноценные документы |
borb выбирают, когда один Python-процесс должен и строить документы из данных, и разбирать уже существующие PDF, а команде подходят программный интерфейс и условия лицензии. PDF Commander удобнее сотруднику, которому нужно открыть файл и исправить его вручную без написания кода. pypdf подходит для надёжных операций со страницами и служебными свойствами, если не нужен сложный визуальный макет.
PyMuPDF стоит рассмотреть для высокой скорости рендера, извлечения и точечных координатных изменений. ReportLab силён в генерации печатных отчётов и обладает зрелой моделью Canvas и Platypus, но обработка чужих PDF не является его основной задачей. pdfplumber полезен аналитикам для таблиц и геометрии текста; для создания счёта или формы ему потребуется другой инструмент.
Практический выбор начинают не со списка функций, а с ведущего сценария. Для ручной правки берут визуальный редактор, для поточного формирования документов — генератор макета, для слияния и шифрования — библиотеку операций со страницами, для извлечения таблиц — аналитический инструмент. Если проект объединяет несколько задач, допустима связка библиотек, но каждый дополнительный пакет должен иметь отдельные тесты и лицензионную проверку.
Как спроектировать рабочий генератор
- Определить обязательные данные, форматы чисел и правила округления до работы с макетом.
- Создать набор стилей для абзацев, заголовков, таблиц и предупреждений.
- Разделить документ на функции, каждая из которых возвращает LayoutElement или контейнер.
- Подготовить локальные шрифты и изображения, проверить лицензии и глифы.
- Добавить тесты на максимальные строки, пустые поля и многостраничные таблицы.
- Писать результат во временный путь, повторно читать его и только затем публиковать.
- Проверять контрольные PDF визуально в нескольких просмотрщиках и на печати.
Первый этап — схема данных. Для счёта это продавец, покупатель, позиции, валюта, налог и сроки; для анкеты — поля и допустимые значения; для отчёта — разделы, метрики и каналы поступления чисел. Каждое поле получает тип и правило отображения. Строка, число, дата и перечисление не должны форматироваться одним универсальным str, потому что локаль и точность различаются.
Второй этап — дизайн-система. Цвета, шрифты, кегли, отступы и радиусы хранят в одном модуле. Функции создают новые элементы, используя эти значения. Это предотвращает ситуацию, когда один заголовок получает 14 пунктов, другой 15, а третий случайный синий. Изменение фирменного цвета становится одной правкой и одним набором визуальных тестов.
Третий этап — компоненты. Шапка, адресный блок, таблица позиций, итог, подпись и колонтитул создаются независимо. Компонент не знает путь выходного файла и не обращается к базе. Он получает готовые данные и возвращает элемент. Благодаря этому его можно построить в тесте, добавить на пустую страницу и сравнить результат с эталоном.
Четвёртый этап — сборка страниц. Генератор решает, какой PageLayout использовать, в каком порядке добавлять компоненты и где создать новый лист. Для длинных таблиц он повторяет шапку. Для приложений меняет ориентацию или размер страницы только в одном явном месте. Номер страницы вычисляют после определения окончательного состава либо применяют предусмотренный механизм колонтитула.
Пятый этап — валидация. До записи проверяют данные, после записи — структуру файла. Визуальный эталон обновляют только после осознанного просмотра изменений. Если тест просто перезаписывает ожидаемую картинку при каждом запуске, он ничего не защищает. Для критических документов изменение эталона проходит ревью вместе с кодом.
Контрольный список перед выпуском документа
- Все обязательные значения присутствуют, даты и суммы отформатированы единообразно.
- Кириллица, знак валюты, кавычки и тире отображаются выбранным шрифтом.
- Длинные строки не выходят за границы, таблицы повторяют заголовки после переноса.
- Изображения имеют достаточное разрешение, но не раздувают размер файла.
- QR-коды и штрихкоды считываются с экрана и распечатки.
- Поля формы имеют уникальные имена и проверены в целевых просмотрщиках.
- Временный файл повторно открывается, число страниц и ключевые строки совпадают.
- В документе нет лишних метаданных, временных путей и тестовых персональных данных.
- Лицензия borb и права на шрифты и изображения соответствуют способу использования.
- Исходный PDF сохранён отдельно, если выполнялось изменение готового документа.
Этот список лучше автоматизировать частично. Программа может проверить существование файла, число страниц, обязательные строки, размер, уникальность полей и отсутствие известных тестовых значений. Сканирование кода и визуальный просмотр остаются ручными или полуавтоматическими. Ответственный сотрудник должен видеть именно тот PDF, который будет отправлен, а не только исходные данные в системе.
Для каждой разновидности документа нужен собственный набор проверок. У билета важны время, место и считывание кода; у счёта — расчёты и реквизиты; у медицинской анкеты — конфиденциальность и заполнение полей; у аналитического отчёта — соответствие графиков числам. Универсальный тест файл открылся полезен, но недостаточен.
Архитектура проекта с borb
В небольшом скрипте допустимо создать документ и записать его в одной функции, но промышленный генератор лучше разделить на уровни. Уровень данных получает заказ, отчёт или анкету и преобразует значения в строгие типы. Уровень представления строит LayoutElement из уже проверенных значений. Уровень вывода создаёт страницы, вызывает PDF.write и выполняет послезагрузочную проверку. Такое разделение исключает запросы к базе во время расчёта ширины таблицы и не позволяет визуальному коду незаметно менять финансовые данные.
Модель данных полезно сделать неизменяемой на время генерации. Если другой поток обновит адрес или список позиций между первой и второй страницей, получится внутренне противоречивый документ. Сначала получают снимок всех нужных значений, фиксируют идентификатор и время, затем строят PDF только из этого снимка. Для большого отчёта данные можно сохранять во временный структурированный файл с контролем доступа, чтобы повторить генерацию без нового запроса к изменившейся системе.
Модуль стилей не должен зависеть от конкретного документа. В нём определяют шрифты, базовые размеры, палитру, стандартные отступы и функции оформления. Модуль компонентов использует стили и создаёт шапку, таблицу, предупреждение, подпись или карточку. Модуль шаблона соединяет компоненты в нужном порядке. Благодаря этому новый тип документа может использовать прежнюю таблицу реквизитов, не копируя десятки параметров.
Ресурсы загружают через отдельный реестр. Он получает логическое имя, например logo_primary или font_body_bold, и возвращает проверенный локальный путь либо объект ресурса. Реестр при запуске проверяет существование файлов и вычисляет их хеши. Если дизайнер заменил шрифт или логотип, изменение обнаруживается до формирования тысячи документов. Сетевые ресурсы сначала помещают в контролируемый кэш с ограничением срока и размера, а в макет передают уже локальную копию.
Для ошибок вводят собственные категории: неверные данные, отсутствующий ресурс, ошибка построения макета, невозможность прочитать исходный PDF и сбой записи. Пользователю не нужно показывать полный traceback, но журнал разработчика должен сохранять тип, этап и идентификатор задания. Персональные значения маскируют. Категории помогают решить, нужно ли повторить задание, исправить данные или остановить очередь из-за общей неисправности шрифта.
Очередь фоновых заданий должна поддерживать идемпотентность. Повтор одного идентификатора не обязан создавать второй документ с другим содержимым. Имя результата связывают с идентификатором шаблона и снимком данных, а перед повторной генерацией проверяют существующий проверенный файл. Если правила требуют новый экземпляр, создают новый идентификатор явно. Такой порядок предотвращает дублирование счетов после временного сетевого сбоя.
Идентификатор шаблона стоит хранить внутри служебных метаданных или рядом с записью о документе. Это не номер borb, а идентификатор собственного макета: invoice_ru_3, report_monthly_2 и подобный. Когда клиент сообщает о переносе строки, команда может восстановить именно тот код и набор ресурсов, которыми был создан файл. Без этой связи визуальная ошибка часто не воспроизводится после изменения дизайна.
Автоматический тест компонента строит минимальный PDF с одним проверяемым блоком. Интеграционный тест формирует полный документ и проверяет структуру. Визуальный тест растрирует страницы и сравнивает их с эталоном, допуская небольшие различия рендера. Отдельный тест извлекает ключевые строки и суммы. Комбинация уровней лучше одного бинарного хеша: PDF может иметь другой внутренний порядок объектов и при этом выглядеть одинаково, либо иметь тот же текст, но неправильные координаты.
Развёртывание в контейнере упрощает повторяемость, если в образ включены точный выпуск Python, зависимости, шрифты и системные библиотеки для дополнительных элементов. Образ не должен запускаться от администратора, а рабочий каталог монтируют отдельно с ограниченной квотой. На старте выполняют самотест: создают одностраничный PDF, читают его обратно и удаляют. Сервис принимает задания только после успешной проверки.
При обновлении зависимостей сначала генерируют контрольный набор и сравнивают страницы. Особое внимание уделяют переносам текста, скруглённым рамкам, формам и встроенным шрифтам, потому что небольшое изменение расчёта размеров может сдвинуть всё содержимое ниже. Обновление выпускают поэтапно, сохраняя возможность вернуть предыдущий образ. Случайное обновление пакета при каждом запуске сервера делает результат непредсказуемым.
Для многоарендного сервиса данные разных клиентов изолируют каталогами и ключами. Общими могут быть только публичные шрифты и фирменные ресурсы самого сервиса. Логотипы клиентов, шаблоны и временные PDF не помещают в глобальный кэш без разграничения доступа. После завершения задания временные файлы удаляют, а журнал подтверждает очистку без записи содержимого.
Наблюдаемость строят вокруг этапов: подготовка данных, загрузка ресурсов, построение элементов, запись, проверка и публикация. Для каждого этапа измеряют время и число ошибок. Рост времени загрузки изображений указывает на сеть, а рост времени PDF.write — на объём или сложность макета. Метрики позволяют исправлять реальную причину, не снижая качество изображений вслепую.
Практический итог
borb особенно полезен там, где PDF является результатом повторяемого процесса, а не единичной ручной правки. Объектная модель Document, Page и LayoutElement позволяет собирать отчёты из проверенных компонентов, PageLayout берёт на себя поток и страницы, таблицы и формы дают структуру, а PDF.read открывает путь к извлечению и изменению готовых файлов. Наибольшую отдачу получают проекты, которые отделяют данные от оформления и поддерживают набор контрольных документов.
Начинать стоит с минимального генератора и одного реального шаблона. После устойчивой работы текста добавляют шрифты, таблицы, изображения и формы по одному, каждый раз проверяя результат. Сложные элементы, OCR, редактирование конфиденциальных данных и Markdown подключают только для конкретной задачи и тестируют отдельно. Такой порядок быстрее выявляет причину ошибки, чем попытка сразу воспроизвести большой макет.
Главные ограничения также практичны: без Python и кода документ не собрать, визуального редактора для перетаскивания блоков нет, а модель лицензирования требует заранее решить вопрос AGPL или коммерческого использования. Если эти условия подходят, borb даёт единый программный подход к созданию, анализу и изменению PDF, который удобно включать в пакетные задания, внутренние системы и серверные конвейеры.
Готовый процесс должен завершаться не только PDF.write, но и проверкой: повторным чтением файла, сверкой обязательного содержимого, просмотром контрольных страниц и безопасной публикацией результата. Именно эта завершающая стадия превращает набор классов макета в надёжное производство документов, где одинаковые входные данные дают предсказуемое оформление, а ошибки обнаруживаются до отправки пользователю.