dxpdf

Быстрый автономный конвертер DOCX в PDF, написанный на Rust и использующий Skia — без Microsoft Office, LibreOffice или облачных API. Доступен как CLI-инструмент, Rust-библиотека и Python-пакет.

RustPython
1Звезда
0Форки
v0.1.4

Проблема

Конвертация документов Word в PDF — одна из самых распространённых задач в бизнес-софте. Счета, договоры, отчёты, формы соответствия — они начинаются как .docx-файлы и должны стать PDF для обмена, архивирования или печати.

Существующие решения имеют значительные компромиссы:

  • Microsoft Office / LibreOffice — требует установки полного офисного пакета на каждый сервер. Headless-режим LibreOffice медленный, потребляет много памяти и даёт непоследовательные результаты между версиями. Масштабирование означает запуск нескольких экземпляров, потребляющих гигабайты оперативной памяти.
  • Облачные API (Google Docs, Adobe, CloudConvert) — добавляют задержку, плату за каждую конвертацию и отправку потенциально конфиденциальных документов на сторонние серверы. Неприемлемо для регулируемых отраслей или изолированных сред.
  • Инструменты HTML-to-PDF (wkhtmltopdf, Puppeteer) — требуют предварительного преобразования DOCX в HTML с потерей точности форматирования. Таблицы, колонтитулы и разрывы страниц редко переживают обратный путь.

Ни одно из этих решений не работает хорошо, когда нужна быстрая, точная, офлайн-конвертация в масштабе — особенно в автоматизированных пайплайнах, CI/CD-системах или встраиваемых приложениях, где установка LibreOffice невозможна.

Как dxpdf решает эту задачу

dxpdf — это автономный конвертер DOCX в PDF, написанный на Rust и использующий графическую библиотеку Google Skia. Он читает .docx-файлы напрямую, парсит OOXML-структуру и рендерит PDF с пиксельной точностью — всё в одном бинарнике без внешних зависимостей кроме Skia.

Вдохновлённый Flutter пайплайн measure-layout-paint обеспечивает соответствие переноса текста, размеров таблиц и разрывов страниц тому, что производит Microsoft Word:

DOCX (ZIP) → Парсинг → Модель документа → Измерение → Вёрстка → Отрисовка → PDF

Результат — конвертер, который выполняет работу за ~115 мс на 3-страничном документе с таблицами и изображениями, используя всего 19 МБ памяти — достаточно быстро для запуска внутри обработчика запросов или пакетной обработки тысяч документов.

Возможности

dxpdf реализует 34 функции OOXML с полным покрытием, включая:

  • Форматирование текста — жирный, курсив, подчёркивание, размер шрифта, гарнитура, цвет, межсимвольный интервал, надстрочный и подстрочный текст, заливка символов
  • Абзацы — выравнивание (по левому краю, по центру, по правому краю), интервалы, отступы, табуляция, границы, заливка
  • Таблицы — ширина столбцов, отступы ячеек с 3-уровневым каскадированием, объединённые ячейки (горизонтальное и вертикальное), высота строк, границы, заливка ячеек, вложенные таблицы
  • Изображения — встроенные (PNG, JPEG, BMP, WebP) и плавающие/привязанные с выравниванием и процентным позиционированием
  • Стили — стили абзацев и символов с наследованием basedOn, настройки документа по умолчанию, шрифты темы
  • Колонтитулы — текст, изображения, номера страниц (коды полей PAGE/NUMPAGES)
  • Списки — маркированные, десятичные, строчные/прописные буквы, строчные/прописные римские с отслеживанием счётчиков
  • Гиперссылки — отображаются как кликабельные PDF-аннотации ссылок
  • Разделы — несколько размеров страниц и полей, разрывы разделов, книжная и альбомная ориентация
  • Вёрстка — автоматическая пагинация, перенос слов, режимы межстрочного интервала, обтекание плавающих изображений

Три способа использования

Инструмент командной строки

Установите и запустите одной командой:

cargo install dxpdf
dxpdf input.docx -o output.pdf

Rust-библиотека

Один вызов функции — байты на вход, байты на выход:

let docx_bytes = std::fs::read("document.docx")?;
let pdf_bytes = dxpdf::convert(&docx_bytes)?;
std::fs::write("output.pdf", &pdf_bytes)?;

Для большего контроля можно просмотреть модель документа перед рендерингом:

use dxpdf::{parse, model};

let document = parse::parse(&std::fs::read("document.docx")?)?;

for block in &document.blocks {
    match block {
        model::Block::Paragraph(p) => { /* inspect paragraph */ }
        model::Block::Table(t) => { /* inspect table */ }
    }
}

let pdf_bytes = dxpdf::convert_document(&document)?;

Python-пакет

Установите с PyPI и используйте в любом Python-приложении:

pip install dxpdf
import dxpdf

# Байты на вход, байты на выход
pdf_bytes = dxpdf.convert(open("input.docx", "rb").read())

# Файл в файл
dxpdf.convert_file("input.docx", "output.pdf")

Производительность

Бенчмарк на Apple M3 Max с hyperfine (20 запусков, 3 прогревочных), конвертация 3-страничного документа с 11 таблицами, 2 изображениями и 2 разделами:

МетрикаЗначение
Среднее время конвертации113 мс
Пиковая память (RSS)19 МБ

Ядро на Rust содержит 104 модульных теста и 9 интеграционных тестов, включая визуальные регрессионные тесты, сравнивающие отрендеренные PDF с эталонными документами, сгенерированными Word.

Сценарии использования

Автоматизированные пайплайны документов

CI/CD-системы или пакетные процессоры, генерирующие договоры, счета или отчёты из .docx-шаблонов. dxpdf запускается как один бинарник — без установки LibreOffice, без Docker-образа с полным десктопным окружением, без стоимости за каждый документ.

Регулируемые среды

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

Встраиваемые системы и edge-вычисления

IoT-устройства, киоски или лёгкие контейнеры, где установка офисного пакета на 500 МБ нецелесообразна. Потребление памяти dxpdf в 19 МБ и субсекундное время конвертации делают его жизнеспособным для сред с ограниченными ресурсами.

Python веб-приложения

Бэкенды на Django, Flask или FastAPI, которым нужно конвертировать загруженные DOCX-файлы на лету. Python-обёртки оборачивают Rust-ядро через PyO3, обеспечивая нативную производительность без подпроцессов или внешних сервисов.

Нет. dxpdf — это автономный конвертер, который читает DOCX-файлы напрямую и рендерит PDF с помощью графического движка Google Skia. У него нет зависимости от какого-либо офисного пакета.

Топ контрибьюторов

thenixan

thenixan

99 commits

Информация о репозитории

Стек технологий
RustPython
Версия
v0.1.4
Лицензия
MIT
Контрибьютор
1
Последнее изменение
21 мар. 2026 г.

Активность

Звезда1
Форки0
Наблюдатель1

Хотите внести вклад?

Посмотреть репозиторий