Спайк A8: растеризатор PDF — hayro (чистый Rust) против pdfium
Сессия A, 2026-10-04. Задача A8 брифа
docs/sessions/A-kernel.md. Решение — предложение в библию (раздел 6). Стенд —kernel/spikes/pdf-bench(отдельное рабочее пространство, в продукт не входит); hayro — из зеркалаmeridian-oss/hayro, коммитced00ddот 2026-10-03.
1. Вопрос
Чем открывать и рисовать чужие PDF в MOffice (просмотр, вставка PDF в
документ, импорт как изображения, сравнение в лаборатории): чистым Rust
— hayro (Apache-2.0 OR MIT, автор krilla, которым мы уже пишем PDF/A) —
или pdfium (C++, Google; из Rust — через
pdfium-render)?
2. Условия
- Машина: Apple M5 Max, macOS 27.0, rustc 1.97.1, release-сборка
(
opt-level 3, thin LTO), один поток. - hayro 0.7 (
ced00dd), настройки по умолчанию (встроенные 14 стандартных шрифтов и CMap), белый фон, 72 dpi. - Эталон —
pdftoppm -r 72из poppler 26.08 (внешний инструмент только для сравнения; GPL-код в продукт не попадает), предел 60 с на файл. - Совпадение — SSIM после размытия 1 px (тот же модуль
meridian_render::ssim, что в замере A5), по общей области при разном размере страниц; до 12 страниц на файл; время — лучшее из 3 прогонов на страницу. - Наборы: 60 PDF корпуса (pdf.js — регрессионные «злые» файлы, Tika — тестовые) и 98 PDF офисных документов (эталоны A5: LibreOffice 26.8 экспортирует docx корпуса).
3. Замеры hayro
| Набор | Файлов | Открыто | Ошибок | Паник | Страниц | SSIM ≥ 0,95 | Средний SSIM | p10 SSIM | Время страницы: медиана / p90 / p99 / макс, мс |
|---|---|---|---|---|---|---|---|---|---|
| Корпус (pdf.js, Tika) | 60 | 58 | 2 | 0 | 80 | 57 из 79 (72,2 %) | 0,966 | 0,914 | 0,31 / 3,42 / 6,09 / 6,09 |
| Офисные PDF (LibreOffice) | 98 | 98 | 0 | 0 | 293 | 263 из 293 (89,8 %) | 0,976 | 0,950 | 1,23 / 3,27 / 7,90 / 26,84 |
- Ошибки открытия — только шифрование:
bug1782186.pdf(Decryption(PasswordProtected)) иtestPDF_no_extract_yes_accessibility_owner_user.pdf(пароль владельца и пользователя). Пароль hayro не принимает — для продукта нужен ввод пароля (свой слой расшифровки или доработка hayro). - Офисные PDF — все 98 документов со средним SSIM ≥ 0,942; страницы ниже 0,95 — сглаживание текста иначе, чем у poppler (геометрия совпадает).
- Расхождения на корпусе (4 страницы ниже 0,9,
картинки —
--out …/low/): размер страницы и положение виджетов форм (bug1802506— флажок и переключатель, другой бокс страницы), фаза мозаичного узора (issue15716— узор Type3-мастей сдвинут), две страницы с тонкими линиями (issue7835,issue11578_reduced). - Устойчивость: стресс-файл
tiling-pattern-tiny-steps-large.pdfhayro рисует за миллисекунды, а poppler считал его больше 9 минут (эталон пришлось ограничить по времени) — для просмотрщика это ровно то, что нужно. - Размер: стенд целиком (hayro + наш
meridian-render+ krilla) — 5,6 МБ исполняемого файла; 132 крейта, все в классах 0–1 (MIT/Apache/BSD-3/Zlib/Unicode-3.0/Unlicense),unsafeв hayro запрещён на уровне крейта.
4. pdfium — не измерен
pdfium-render и сборок pdfium в зеркалах
meridian-oss нет (проверено git ls-remote:
pdfium-render, pdfium,
pdfium-binaries и др. — «Cannot find repository»), а
правило проекта — чужой код только из зеркал. Поэтому замер pdfium
отложен; запрос на зеркала — во «Входящих» B-log. Что известно без
замера:
| hayro | pdfium через pdfium-render |
|
|---|---|---|
| Язык, безопасность | Rust, #![forbid(unsafe_code)] |
C++ (оценка: сотни тысяч строк с зависимостями), FFI; уязвимости закрываются вместе с Chrome |
| Лицензия | Apache-2.0 OR MIT | BSD-3 + Apache-2.0 (pdfium), MIT/Apache
(pdfium-render) |
| Сборка на 3 ОС и arm64 | cargo build |
готовые двоичные pdfium (оценка: 5–7 МБ на платформу) или сборка Chromium-инструментами (gn/ninja) |
| Детерминизм между ОС | один код растеризации (vello_cpu) | одинаковый код, но свои SIMD-пути |
| Шифрование, формы, JS | шифрование — нет (п. 3), формы — внешний вид виджетов, JS — нет | полно |
| Зрелость | молодой (0.7), ≥ 1 000 регрессионных файлов pdf.js/PDFBox | движок Chrome |
5. Выводы
- hayro готов как основной растеризатор PDF для просмотра и вставки PDF: 156 из 158 файлов, 0 паник, 90 % страниц офисных PDF совпадают с poppler по SSIM ≥ 0,95, медиана — 1,2 мс на страницу при 72 dpi, в одном дереве крейтов с krilla (тот же автор; skrifa 0.46 — та же версия, что у нашего растра).
- Пробелы hayro — шифрование PDF и тонкие места
(формы, узоры). Шифрование закрываем сами (RC4/AES-128/256 по ISO 32000
— небольшой объём, есть криптопримитивы в
meridian-crypto) или доработкой в зеркале с отправкой изменений автору. - pdfium оставляем запасным вариантом за флагом сборки только если в фазе 1 найдутся классы документов, где hayro заметно хуже; сравнить на тех же наборах, как только появятся зеркала.
6. Предложение в библию
«Растеризатор PDF — hayro (чистый Rust, зеркало
meridian-oss/hayro); расшифровку защищённых PDF делает
ядро. pdfium — только как запасной путь за флагом сборки, после замера
на корпусе».
7. Риски
- Молодой проект с одним основным автором: держим зеркало, фаззинг
своих входов (
kernel/fuzz) распространяем на PDF, изменения отправляем в исходный проект. - Совпадение «с poppler» ≠ «с Acrobat»: для M0.4 нужны эталоны Acrobat/Word на части набора.
8. Как воспроизвести
cd kernel/spikes/pdf-bench
cargo run --release -- ../../../tests/corpus/private/pdf --out /tmp/pdf-bench-corpus
cargo run --release -- ../../../tests/corpus/private/refs/libreoffice --out /tmp/pdf-bench-officeИтог — в stdout, по файлам — results.tsv, страницы с
SSIM < 0,9 — low/*.png («hayro | эталон»). Нужен
pdftoppm (poppler) в PATH — только для
эталона.