GraphCompose: как разделить layout и рендеринг для генерации документов в PDF, Word и Excel
Создание документов, которые выглядят одинаково в разных форматах, — задача, с которой сталкиваются многие разработчики. Обычно для каждого формата приходится писать отдельный код, что ведёт к дублированию и ошибкам. Разработчик под ником GraphCompose решил эту проблему, создав систему, где layout e

Создание документов, которые выглядят одинаково в разных форматах, — задача, с которой сталкиваются многие разработчики. Обычно для каждого формата приходится писать отдельный код, что ведёт к дублированию и ошибкам. Разработчик под ником GraphCompose решил эту проблему, создав систему, где layout engine рассчитывает геометрию один раз, а подключаемые backend’и переводят её в нативные объекты нужного формата. В своей статье на Habr он подробно описал, как отделил layout engine от PDFBox и Apache POI, и как это изменило архитектуру проекта.
Как GraphCompose отделил layout engine от PDFBox и Apache POI
Изначально GraphCompose был тесно связан с PDFBox: весь код по расчёту расположения элементов (layout) был перемешан с кодом рендеринга в PDF. Разработчик осознал, что это ограничивает возможности — добавить поддержку Word или Excel означало бы переписывать всё с нуля. Поэтому он решил разделить эти две части: layout engine теперь работает независимо, а для каждого формата создаётся отдельный backend, который получает готовую геометрию и преобразует её в нативные объекты. PDFBox остаётся одним из backend’ов, но больше не является ядром системы. Apache POI используется для генерации форматов Microsoft Office.
Предыстория и контекст
Проблема унификации документов не нова. Существуют решения вроде LaTeX, XSL-FO или коммерческих продуктов, но они либо сложны в настройке, либо привязаны к одному формату. GraphCompose начинался как хобби-проект для генерации PDF-отчётов, но со временем стало ясно, что пользователям нужны и другие форматы — Word для редактирования, Excel для данных. Разработчик выбрал архитектуру, где layout engine отвечает только за расчёт позиций и размеров элементов, а рендеринг делегируется плагинам. Это напоминает подход, используемый в веб-браузерах (Blink + разные рендеры), но для документов.
Чем это отличается от традиционных генераторов документов?
Традиционные генераторы (например, iText или Apache POI напрямую) требуют писать код под каждый формат отдельно. В GraphCompose вы описываете документ на едином языке, который включает текстовые блоки, таблицы, изображения, списки и т.д. Layout engine вычисляет, где каждый элемент должен находиться на странице, учитывая переносы строк, разрывы страниц и другие правила. Затем backend форматирует эту геометрию в соответствии с возможностями целевого формата. Это означает, что один и тот же документ может быть экспортирован в PDF, DOCX, XLSX и другие форматы без изменения исходного кода.
Технические детали: как устроен layout engine и backend’и
Layout engine работает с абстрактным деревом документа, где каждый узел — это элемент с определёнными свойствами (ширина, высота, отступы, тип содержимого). Engine обходит дерево и вычисляет точные координаты для каждого элемента, учитывая алгоритмы переноса строк и разбиения на страницы. Результат — плоский список геометрических примитивов (прямоугольники, линии, текст с координатами). Backend берёт этот список и транслирует его в API целевой библиотеки: для PDF — PDFBox, для DOCX — POI XWPF, для XLSX — POI XSSF. Разработчик отмечает, что основная сложность — это обработка специфических для формата ограничений, например, в Excel нет произвольного позиционирования, поэтому таблицы приходится эмулировать через объединение ячеек.
Какие проблемы решает разделение layout и рендеринга?
Главная проблема, которую решает такой подход, — это дублирование кода. Если вы пишете генерацию PDF, а затем хотите добавить Word, вам не нужно переписывать логику расположения элементов — достаточно реализовать новый backend, который преобразует готовую геометрию в формат Word. Это также упрощает тестирование: layout engine можно тестировать независимо от рендеринга. Кроме того, изменение дизайна документа (например, добавление нового типа элемента) требует правки только в layout engine и во всех backend’ах, но не в каждом генераторе отдельно.
Кого затронет и как
Разработчики, которые создают отчёты, счета, договоры или любые другие документы с программной генерацией, смогут сократить время разработки и упростить поддержку. Для бизнеса это означает единый источник правды: изменения в описании документа автоматически применяются ко всем форматам. Пользователи в России и СНГ, где часто требуются документы в форматах Word и Excel, также выиграют — не придётся писать отдельные модули для каждого формата. Конкуренты вроде FastReport или Crystal Reports могут обратить внимание на этот подход, но GraphCompose пока остаётся open-source проектом.
Что будет дальше
Разработчик планирует добавить поддержку HTML и Markdown в качестве backend’ов, а также улучшить обработку сложных макетов, таких как многостраничные таблицы и колонтитулы. В перспективе возможно создание визуального редактора, который будет генерировать код на языке описания. Сейчас проект находится в стадии бета-тестирования, и автор приглашает сообщество к участию.
Итог
GraphCompose предлагает элегантное решение давней проблемы: отделение layout от рендеринга. Это делает генерацию документов более гибкой и масштабируемой. Если проект получит поддержку сообщества, он может стать стандартом для генерации мультиформатных документов в Java-мире.