Новости · Релизы

pypdf 6.16.0: аннотации PDF поворачиваются на произвольный угол

13 августа 2026 вышел pypdf 6.16.0 — очередное обновление популярной Python-библиотеки для работы с PDF. Релиз приносит два значимых изменения: аннотации с внешним видом (AppearanceStream) теперь корректно поворачиваются под любым углом, а не только кратным 90°, и добавлена защита от зависания при вставке объектов в дерево TreeObject, если в PDF оказалась кольцевая ссылка.

Коротко: pypdf 6.16.0 от 13 августа 2026 добавляет два исправления. Первое — аннотации PDF поворачиваются на произвольный угол (ранее только 0°, 90°, 180°, 270°). Второе — защита от зависания: если PDF содержит циклическую ссылку в дереве объектов, метод TreeObject.insert_child теперь обнаруживает петлю и прерывает обход вместо бесконечного цикла.

15 августа 2026 Редакция LoadFile Чтение 5 мин
Цветные геометрические фигуры с указателями вращения на бумаге — аннотации PDF в pypdf 6.16.0
Содержание
  1. Что нового в 6.16.0
  2. Вращение аннотаций: почему это важно
  3. Защита от циклических деревьев объектов
  4. Контекст: pypdf в серверных пайплайнах
  5. Что делать
  6. Источники

Что нового в 6.16.0

pypdf — «чистая» Python-библиотека для работы с PDF-файлами: объединяет, разрезает, извлекает текст и страницы, управляет аннотациями и метаданными. Предыдущая версия 6.15.0 вышла 6 августа 2026. Спустя неделю, 13 августа, разработчики опубликовали 6.16.0 с двумя целевыми исправлениями.

Первое касается AppearanceStream — механизма задания внешнего вида аннотаций в формате PDF. До 6.16.0 библиотека корректно применяла поворот только для стандартных значений: 0°, 90°, 180° и 270°. Любой другой угол обрабатывался некорректно — внешний вид аннотации не совпадал с ожидаемым. Теперь поддерживается произвольный угол вращения.

Второе исправление относится к надёжности: метод insert_child объекта TreeObject получил обнаружение кольцевых ссылок. Если дерево объектов в PDF содержит петлю — узел ссылается на самого себя или на предка — метод теперь прерывает обход, вместо того чтобы уходить в бесконечный цикл. Исправление закрывает баг #3964, зафиксированный в трекере проекта.

Вращение аннотаций: почему это важно

Аннотации в PDF — это наложенные на страницу элементы: текстовые пометки, выделения, штампы, формы, подписи и другие объекты. Каждая аннотация может иметь собственный AppearanceStream — поток описания внешнего вида, который задаёт, как именно она должна выглядеть при рендеринге: размер, положение, шрифт, цвет и в том числе угол поворота.

Спецификация PDF допускает произвольный угол вращения аннотации через матрицу трансформации. На практике большинство аннотаций повёрнуты на стандартные значения: горизонтально (0°), вертикально (90° или 270°) или вверх ногами (180°). Однако в реальных документах встречаются и нестандартные углы — например, в технических чертежах с диагональными пометками, в юридических документах со штампами под углом или в формах, где поле подписи намеренно наклонено.

Когда pypdf применял AppearanceStream с нестандартным углом, трансформация рассчитывалась неверно: аннотация оказывалась не там и не так, как задумано. При программном создании PDF-документов с такими аннотациями итоговый файл отображался в просмотрщиках с видимыми артефактами. Теперь библиотека корректно вычисляет матрицу для произвольного угла — вывод соответствует ожидаемому положению.

i
AppearanceStream и рендеринг аннотаций

AppearanceStream — это необязательный, но важный компонент аннотации в PDF. Если он задан, просмотрщик использует именно его для отображения, игнорируя собственный стиль по умолчанию. Библиотеки-генераторы PDF, такие как pypdf, должны корректно строить этот поток, иначе результат зависит от того, насколько снисходительно каждый просмотрщик трактует неверную матрицу.

Защита от циклических деревьев объектов

PDF-документ устроен как граф взаимосвязанных объектов: страницы, шрифты, изображения, аннотации, аутлайн-дерево (оглавление) и другие структуры связаны между собой ссылками. В корректном PDF эти связи образуют направленный граф без циклов. Но в повреждённом, намеренно собранном или некорректно экспортированном файле узлы могут ссылаться на самих себя или на своих предков — образуется кольцо.

Если программа обходит такую структуру без проверки посещённых узлов, она входит в бесконечный цикл: обход идёт по кругу, процесс не завершается, процессор загружается полностью. Именно такой сценарий описывал баг #3964 в трекере pypdf: метод TreeObject.insert_child, отвечающий за вставку нового узла в дерево объектов, не проверял, не попал ли он уже в эту ветку дерева.

В версии 6.16.0 метод получил проверку посещённых узлов: при обходе дерева библиотека запоминает пройденные элементы и прерывает операцию, если один из них встречается повторно. Это тот же класс защиты, что был добавлен ранее для других частей pypdf — в частности, для нитей-статей (article threads) в релизе 6.13.1. Паттерн повторяется, потому что PDF по природе формата допускает циклические ссылки в нескольких независимых структурах, и каждую из них нужно защищать отдельно.

!
Чем это отличается от CVE-2026-54651

В июле 2026 был закрыт баг CVE-2026-54651 — тоже зависание в pypdf, но в другом месте: функция _add_articles_thread при слиянии файлов с круговыми нитями-статьями. Баг #3964 из 6.16.0 — самостоятельное исправление другого метода TreeObject.insert_child. У него нет присвоенного CVE, он не классифицирован как уязвимость безопасности: злоумышленнику потребовался бы PDF, принятый конкретно через insert_child, что менее распространено в типовых пайплайнах.

Контекст: pypdf в серверных пайплайнах

pypdf — одна из наиболее используемых Python-библиотек для работы с PDF. Она не требует сторонних зависимостей и работает на любой платформе, где есть Python. Это делает её популярным выбором для автоматизации: генераторы отчётов, онлайн-конвертеры, системы документооборота, пайплайны извлечения данных из PDF, чат-боты и агенты, обрабатывающие присланные документы.

Именно из-за широкого распространения история pypdf в 2026 году насыщена точечными патчами: несколько версий подряд закрывали варианты бесконечных циклов при обработке специально собранных файлов. Логика здесь одна: библиотека принимает входные данные из ненадёжных источников, и любой нераскрытый путь к зависанию — это потенциальный вектор отказа в обслуживании. Об этой серии подробнее написано в нашей статье о CVE-2026-54651.

Для серверных приложений, которые принимают PDF от пользователей, своевременные обновления pypdf важнее, чем для десктопных инструментов. Одна входящая «петля» в дереве объектов может занять рабочий процесс целиком. Библиотека с защитой от циклов завершит операцию с ошибкой вместо зависания — это предсказуемое поведение, с которым приложение может справиться. Подробнее о том, каких форматов файлов стоит опасаться на сервере: раздел безопасность файлов.

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

Что делать

  1. Обновите pypdf до версии 6.16.0: pip install --upgrade pypdf. Проверить текущую версию: pip show pypdf.
  2. Если ваше приложение генерирует PDF с аннотациями под нестандартными углами, проверьте результат после обновления — рендеринг должен совпасть с ожидаемым положением аннотации.
  3. Если pypdf используется для обработки входящих PDF от пользователей, обновление снижает риск зависания на файлах с циклическими деревьями объектов. Тем не менее рекомендуется сохранять тайм-аут на операции обработки PDF и изолировать обработку в отдельном процессе с ограничением ресурсов.
  4. Проверьте транзитивные зависимости: pypdf часто подтягивается как зависимость других пакетов. Команда pip list | grep pypdf покажет установленную версию во всём окружении; pip-audit — известные уязвимости.

Источники

Данные приведены на 15 августа 2026 по материалам официального репозитория pypdf на GitHub. Версия 6.16.0 опубликована 13 августа 2026. Номер бага #3964 указан по трекеру проекта.

Читайте также