PyMuPDF помогает извлекать текст и таблицы из PDF, искать фразы по координатам, превращать страницы в изображения, объединять и переставлять листы, заполнять формы, добавлять аннотации и необратимо удалять конфиденциальные данные. Основные инструменты — объекты Document и Page, геометрия Rect и Quad, структурированные режимы get_text(), рендеринг get_pixmap(), поиск search_for(), таблицы find_tables(), виджеты форм и операции сохранения с очисткой и сжатием.
Рабочий процесс строится вокруг коротких Python-сценариев: документ открывают, выбирают страницу, вызывают нужный метод, проверяют возвращённые прямоугольники, словари или объекты, а затем сохраняют результат в новый файл. Для разовой диагностики подходят интерактивная консоль и ноутбук, для повторяемой обработки — отдельный модуль с журналом ошибок, проверкой входных данных и тестовыми PDF.
Вместо набора окон с кнопками пользователь получает программный интерфейс, где каждый шаг можно воспроизвести и встроить в обработчик документов. Это особенно удобно для пакетных задач, но требует понимания Python, координат страницы и различий между визуальным перекрытием, аннотацией и реальным изменением содержимого PDF.
Скачать PyMuPDF
- Редактирование PDF
- Русский интерфейс
- Просто новичкам
- Нет готового PDF-интерфейса
- OCR требует Tesseract
- Нет многопоточности
Как устроен рабочий процесс
Центральный объект Document представляет открытый файл или создаваемый контейнер страниц. Через него получают количество страниц, метаданные, оглавление, вложения, разрешения и низкоуровневые объекты. Индексация начинается с нуля, поэтому первая страница доступна как doc[0], а последняя — как doc[-1]. Объект Page живёт в контексте документа: после закрытия файла или структурного изменения ссылки на старые страницы, аннотации и виджеты могут стать осиротевшими, поэтому их получают заново после вставки, удаления или перестановки листов.
Для визуального результата Page преобразуется в Pixmap. Для анализа текста метод get_text() возвращает строку, блоки, слова, HTML, XML либо словарь с блоками, строками и фрагментами. Геометрические методы используют Rect, Point, Quad и Matrix. Такое разделение позволяет один раз найти объект, а затем теми же координатами сделать вырезку, подсветку, комментарий или редактирование.
Хороший сценарий не ограничивается вызовом одного метода. Он проверяет, что документ открылся, номер страницы попадает в диапазон, найденные прямоугольники не пусты, выходной путь отличается от исходного при полном сохранении, а итоговый файл повторно открывается. Для пакетной обработки записывают имя входного файла, число страниц, длительность каждого этапа и количество найденных элементов.

Минимальная проверка документа
После открытия читают page_count, metadata и get_toc(). Пустые метаданные не означают повреждение файла, а отсутствие оглавления не мешает извлечению. Исключение при открытии чаще указывает на неверный путь, неподдерживаемый контейнер, пароль или серьёзную ошибку структуры. Предупреждения MuPDF собирают отдельно: документ может открыться после восстановления, но при сохранении его следует проверить ещё раз.
Почему координаты важнее номера строки
PDF хранит графические команды, а не абзацы в редакторском смысле. Два слова, которые визуально стоят рядом, могут быть записаны разными операциями и в неожиданном порядке. Поэтому надёжные сценарии используют не только текст, но и его прямоугольник, размер шрифта, направление строки и положение относительно других блоков.
Установка и первая диагностика
Для изолированного проекта создают виртуальное окружение, активируют его и устанавливают пакет командой python -m pip install --upgrade pymupdf. Такой вариант привязывает pip к выбранному интерпретатору и уменьшает риск, что библиотека окажется в другом окружении. Затем выполняют python -c "import pymupdf; print(pymupdf.__doc__)" или короткий сценарий открытия тестового PDF.
Если импорт проходит в терминале, но не работает в IDE или ноутбуке, почти всегда используются разные интерпретаторы. Нужно сравнить sys.executable внутри проблемной среды и путь, куда установил пакет python -m pip show pymupdf. После смены ядра ноутбука или интерпретатора проекта процесс перезапускают, иначе в памяти может оставаться прежний набор модулей.
Готовые колёса выпускаются для распространённых конфигураций CPython на Windows, macOS и Linux. При отсутствии подходящего пакета pip пытается собрать расширение из исходников, что требует компилятора и дополнительных компонентов. Сначала обновляют pip, проверяют разрядность Python и убеждаются, что выбран поддерживаемый CPython с совместимым ABI.
Проверка импорта без конфликта имён
В рабочей папке не должно быть файлов pymupdf.py или каталогов pymupdf, созданных пользователем: они перекрывают установленный пакет. Аналогичная проблема возникает, если сценарий назван fitz.py. При странном импорте выводят pymupdf.__file__ и удаляют локальные совпадающие имена вместе с каталогом __pycache__.
Безопасное обновление проекта
Перед обновлением фиксируют зависимости и прогоняют тесты на репрезентативных PDF: цифровых, сканированных, с формами, нестандартными шрифтами и повреждённой структурой. Для производственного сервиса диапазон версии закрепляют в файле зависимостей и меняют осознанно, а не получают новую сборку при каждом развёртывании.
Открытие PDF и других документов
Обычный файл открывают через pymupdf.open(path). Источником также может быть байтовая строка или поток, что удобно при получении документа из базы данных, очереди или хранилища. При открытии из памяти указывают тип, если он не определяется по содержимому. После обработки документ закрывают контекстным менеджером, чтобы освободить дескриптор и память.
Помимо PDF движок читает XPS, EPUB, CBZ, MOBI, FB2, SVG и ряд текстовых и растровых форматов. Набор доступных операций зависит от типа: интерактивные формы и аннотации относятся к PDF, а потоковый документ может быть доступен прежде всего для чтения и преобразования. Перед универсальной обработкой проверяют doc.is_pdf и не применяют PDF-специфичные операции ко всем входам.
Документ с паролем может открыться в состоянии, где страницы недоступны до аутентификации. Метод authenticate() принимает пароль и возвращает признак уровня доступа. Сценарий различает неверный пароль, отсутствие пароля и ограничения разрешений. Даже когда операция технически возможна, учитывают правомерность обработки и требования владельца.
Открытие из байтов
Потоковый режим полезен, когда нельзя создавать временный файл. Однако вся байтовая строка находится в памяти, поэтому для крупных документов оценивают расход памяти и ограничивают максимальный размер входа. Если источник ненадёжен, сначала проверяют сигнатуру, длину и тип содержимого, затем передают байты движку.
Восстановление проблемных PDF
MuPDF читает многие файлы с нарушенной таблицей перекрёстных ссылок и может восстановить структуру. Это не повод игнорировать предупреждения: после открытия такой документ сохраняют в новый файл с очисткой мусора и сжатием, снова открывают результат и сверяют число страниц, текст и изображения на контрольных листах.
Навигация по страницам и система координат
Размер страницы доступен через page.rect, а видимая область зависит от MediaBox и CropBox. Координаты в большинстве высокоуровневых методов отсчитываются от левого верхнего угла, ось X направлена вправо, ось Y — вниз, единицей служит пункт. При рендеринге Matrix или dpi переводит пункты в пиксели, поэтому прямоугольник из поиска нельзя без преобразования накладывать на произвольно масштабированное изображение.
Поворот страницы влияет на отображение, но внутренние координаты методов обычно нормализованы. Для обмена геометрией с другой библиотекой или просмотрщиком учитывают rotation_matrix и derotation_matrix. Ошибка проявляется как рамка, уехавшая на соседний край, или как вырезка другого участка.
Для обхода используют for page in doc, но при изменении структуры безопаснее работать с индексами и заново получать объект страницы. Вставка, удаление, select() или move_page() могут инвалидировать сохранённые объекты Page, Annot и Widget. Это одна из типовых причин сообщения об orphaned object.
Прямоугольники и четырёхугольники
Rect подходит для горизонтальных областей, клипов и рамок. Quad сохраняет четыре вершины и лучше описывает наклонный или повернутый текст. Поиск с quads=True полезен для подсветки строк, потому что аннотация повторяет направление текста, а не закрывает его грубым прямоугольником.
Ограничение области обработки
Параметр clip сокращает объём анализа и помогает отделить тело таблицы от заголовка страницы. Сначала область определяют визуально, затем сохраняют как конфигурацию в координатах PDF. Для документов разных размеров абсолютный Rect заменяют относительными долями ширины и высоты, но итоговую область проверяют на каждой группе шаблонов.
Извлечение текста: от строки до структуры
В режиме text возвращается сплошная строка с переводами строк и разделителями страниц. Это быстрый вариант для полнотекстового индекса, предварительной классификации и поиска ключевых слов. Он не хранит координаты и оформление, поэтому по нему нельзя понять, где находилась фраза и какой шрифт использовался.
Режим blocks выдаёт прямоугольники и текстовые блоки, что удобно для грубой сегментации. Режим words разбивает текст на слова и дополняет каждое координатами, номером блока, строки и слова. Его используют для восстановления табличных строк, поиска значения справа от метки и построения собственного порядка чтения.
Структурированный словарь dict раскрывает блоки, строки и spans. Для каждого фрагмента доступны текст, прямоугольник, размер и имя шрифта, цвет и флаги оформления. rawdict идёт глубже и хранит символы, что нужно для точной типографской диагностики, но заметно увеличивает объём данных. Форматы HTML и XML полезны для преобразования, однако результат проверяют на сложной вёрстке.

Сортировка и порядок чтения
Параметр sort=True пытается расположить элементы сверху вниз и слева направо. На одноколоночных страницах этого часто достаточно, но журнальная вёрстка, боковые примечания и плавающие подписи требуют собственного алгоритма. Практический подход — кластеризовать блоки по колонкам, удалить повторяющиеся колонтитулы и только затем соединять строки.
Повторное использование TextPage
Если для одной страницы выполняются несколько поисков и извлечений, выгодно один раз построить TextPage и передавать его в последующие вызовы. Это сокращает повторный разбор. TextPage должен соответствовать той же странице и параметрам: после изменения содержимого старый объект уже не отражает новый документ.
Шрифты, пробелы, лигатуры и переносы
PDF может хранить слово как последовательность символов без обычных пробелов, а визуальный пробел определяется расстоянием между глифами. В другом файле пробелы присутствуют в текстовом потоке, но шрифт использует нестандартную таблицу Unicode. Поэтому качество извлечения зависит не только от библиотеки, но и от способа создания документа.
Лигатуры вроде fi могут возвращаться одним символом или разворачиваться в два в зависимости от флагов извлечения. Переносы на конце строки требуют отдельного решения: для полнотекстового поиска слово иногда соединяют, если первая часть заканчивается дефисом, но в артикулах и кодах дефис значим. Универсальное удаление дефисов портит данные.
Отсутствующие глифы, квадраты и неправильные буквы при вставке текста означают, что выбранный шрифт не содержит нужных символов или используется неверная кодировка. Для кириллицы и специальных знаков подключают подходящий файл шрифта, используют согласованное имя ресурса и проверяют итоговый PDF рендерингом, а не только повторным извлечением.
Поиск фразы, разбитой на строки
search_for() умеет находить некоторые переносы и нормализовать регистр ASCII, но сложные сочетания проверяют на конкретных документах. Надёжный вариант для критичных данных — извлечь слова с координатами, собрать последовательности по строкам и сопоставить нормализованный текст, сохранив объединённую геометрию найденных слов.
Колонтитулы и номера страниц
Повторяющийся верхний или нижний текст удаляют по координатам и частоте появления. Если одинаковая строка встречается на большинстве страниц в узкой полосе у края, её можно считать колонтитулом. Нельзя отбрасывать все короткие строки: в таблицах они могут быть кодами, датами и суммами.
Поиск текста и работа с геометрией
page.search_for("фраза") возвращает список прямоугольников, где обнаружено совпадение. Полученные области передают в add_highlight_annot(), используют как clip для увеличенного рендера или расширяют перед редактированием. Перед массовым действием выводят число совпадений и сохраняют контрольный снимок: одинаковое слово может встречаться в заголовке, таблице и примечании.
Поиск не является механизмом регулярных выражений. Для шаблонов, например номеров договоров, сначала извлекают слова или текст, выполняют регулярное выражение, а затем сопоставляют совпадение с геометрией. Простое соответствие по символьным позициям ненадёжно после нормализации, поэтому для точных задач строят последовательность слов и сохраняют диапазоны.
Прямоугольник результата иногда расширяют на один-два пункта, чтобы аннотация не обрезала край глифа. Слишком большое расширение затрагивает соседнюю строку. Для повернутого текста предпочтительны quads: они задают ориентацию и дают корректную форму подсветки.

Проверка результата поиска
После операции документ открывают заново и повторяют поиск. Для подсветки совпадение должно оставаться, для редактирования — исчезнуть. Дополнительно проверяют извлечённый текст и пиксельный рендер, потому что один метод подтверждает структуру, а другой — внешний вид.
Нормализация регистра и символов
Сравнение осложняют неразрывные пробелы, похожие тире, составные диакритические знаки и символы из частных кодировок. Перед логическим сравнением допустима Unicode-нормализация и замена пробельных последовательностей, но исходную строку и координаты сохраняют для аудита.
Поиск и извлечение таблиц
page.find_tables() анализирует линии и расположение текста, возвращая объект поиска и найденные таблицы. Для каждой таблицы доступны границы, ячейки, извлечённые строки и преобразование в DataFrame. На документах с явной сеткой результат обычно стабилен; на таблицах без линий многое зависит от выравнивания слов и пробелов.
Перед выгрузкой проверяют число столбцов, заголовок и объединённые ячейки. Пустая ячейка может означать настоящий пропуск, продолжение объединённого заголовка или ошибку детектора. Числа сохраняют сначала строками, затем отдельно нормализуют разделители тысяч, десятичный знак, валюту и отрицательные значения в скобках.
Если на странице несколько таблиц, их различают по bbox и ближайшему заголовку. Для повторяющегося шаблона ограничивают поиск clip-областью, чтобы линии рамки страницы или диаграммы не воспринимались как сетка. Многостраничные таблицы объединяют только после проверки одинаковой схемы столбцов и удаления повторного заголовка.

Таблицы без границ
Когда сетки нет, используют координаты слов: группируют их по близким Y, определяют устойчивые X-позиции столбцов и собирают значения по интервалам. Алгоритм требует допусков, зависящих от размера шрифта. Его тестируют на строках с длинным описанием, которое переносится на две линии.
Экспорт в CSV и Excel
DataFrame удобен для последующей очистки, но преобразование не исправляет распознавание. До экспорта добавляют номер страницы, bbox таблицы и идентификатор исходного файла. Эти поля помогают вернуться к первоисточнику, если проверка обнаружит спорную сумму.
Рендеринг страниц в изображения
page.get_pixmap() выполняет растеризацию. По умолчанию получается изображение экранного масштаба; параметр dpi задаёт предсказуемое разрешение, а Matrix позволяет масштабировать и поворачивать. Для миниатюр достаточно умеренного DPI, для печати и OCR нужен более высокий, но расход памяти растёт пропорционально числу пикселей.
Параметр colorspace выбирает RGB, серый или CMYK, а alpha определяет наличие прозрачности. Для обычного PNG прозрачность часто не нужна: alpha=False экономит память и даёт непрозрачный фон. Если страница должна накладываться на другой фон, альфа-канал сохраняют осознанно.
Параметр clip рендерит только прямоугольный участок. Это полезно для увеличенных фрагментов, распознавания отдельной таблицы и проверки редактирования. Координаты clip задаются в системе страницы, а размеры в пикселях определяются масштабом. Перед сохранением clip пересекают с page.rect, чтобы не получить пустую область.

Баланс качества и памяти
Страница A4 при 300 dpi содержит около девяти миллионов пикселей. RGB без альфы требует примерно три байта на пиксель до учёта служебных структур, поэтому параллельный рендер десятков страниц быстро расходует память. Обработчик ограничивает число процессов, сохраняет результат по мере готовности и освобождает промежуточные Pixmap.
Антиалиасинг и тонкие линии
На маленьких миниатюрах тонкие линии таблицы могут исчезать, а мелкий текст становится серым. Это не обязательно повреждение PDF. Для проверки увеличивают DPI или рендерят небольшой clip. Если линии нужны машинному зрению, выбирают масштаб, где толщина становится хотя бы двумя пикселями.
Извлечение встроенных изображений
page.get_images(full=True) перечисляет ссылки на растровые объекты страницы, а doc.extract_image(xref) возвращает исходные байты и описание формата. Такой способ сохраняет оригинальное сжатие лучше, чем рендер страницы. Один xref может использоваться многократно, поэтому список дедуплицируют и отдельно получают места размещения через get_image_rects().
Не вся видимая графика является изображением. Логотип бывает векторными контурами, диаграмма — набором линий и заливок, а фон — встроенной формой XObject. Если get_images() возвращает пусто, но на странице видна иллюстрация, исследуют get_drawings() или рендерят нужную область.
Маски прозрачности требуют аккуратной сборки: базовое изображение и soft mask могут быть отдельными объектами. extract_image часто возвращает пригодный файл, но для необычных PDF проверяют фон и прозрачные края. Сохранённые изображения сравнивают по размеру, формату и хэшу, чтобы не создавать десятки одинаковых файлов.

Почему изображение может быть мёртвым
В таблице объектов встречаются неиспользуемые ресурсы, оставшиеся после редактирования. Page.get_images() отражает ресурсы страницы, но не гарантирует, что каждый действительно видим. Проверка через get_image_rects() и рендер отделяет размещённые изображения от мусора.
Снимок области вместо исходного объекта
Когда нужна композиция вместе с подписями и рамками, извлечение xref не подходит: оно отдаёт только растровый ресурс. Тогда рендерят clip, включающий изображение и окружающие элементы. Разрешение выбирают по конечному размеру, чтобы не увеличивать низкокачественный исходник без пользы.
Слияние, разделение и перестановка страниц
Для копирования страниц из одного PDF в другой используется insert_pdf(). Можно задать диапазон, порядок и повторить страницы. При объединении нескольких документов заранее решают, как поступать с метаданными, оглавлением, именованными ссылками, формами и вложениями: перенос страниц не всегда означает автоматическое объединение всех структур верхнего уровня.
Метод select() оставляет страницы в заданной последовательности и подходит для перестановки или повторения. delete_page() и delete_pages() удаляют листы, move_page() перемещает. После структурных операций старые ссылки на Page, Annot и Widget считают недействительными и получают заново.
Для размещения страницы PDF внутри новой страницы применяется show_pdf_page(). В отличие от растеризации, этот путь сохраняет векторный текст и графику, позволяет масштабировать и поворачивать исходный лист. Он подходит для компоновки нескольких страниц на одной, буклетов и водяных знаков из PDF-шаблона.
Оглавление после сборки
После объединения оглавления исходников пересчитывают номера страниц. Алгоритм хранит смещение каждого входного документа, добавляет его к номеру каждой записи и при необходимости вводит верхний уровень с именем файла. Итоговый список проверяют: номера должны находиться от 1 до page_count.
Разделение без потери контроля
При разбиении для каждого результата записывают исходный диапазон страниц и хэш входа. Имена формируют из безопасных идентификаторов, а не произвольного текста документа. После сохранения открывают каждый фрагмент и сверяют количество листов.
Создание страниц, текста и графики
Новый PDF создаётся пустым Document, после чего new_page() добавляет лист нужного размера. insert_text() подходит для короткой строки в заданной точке, insert_textbox() размещает текст внутри прямоугольника и сообщает, поместился ли он. Отрицательный результат textbox означает переполнение; его нельзя игнорировать, иначе часть текста исчезнет.
Shape объединяет линии, прямоугольники, кривые, заливки и текстовые операции перед фиксацией на странице. Это уменьшает число отдельных команд и удобно для рамок, схем и отметок. TextWriter эффективен для большого количества позиционированного текста и повторного использования шрифта.
При вставке кириллицы, математических символов или азиатских письменностей выбирают шрифт с нужными глифами. Встроенные базовые PDF-шрифты покрывают ограниченный набор. Файл шрифта подключают явно, соблюдая его лицензию, затем проверяют рендер и обратное извлечение текста.
Единицы и базовая линия
Координата insert_text() задаёт базовую линию, а не верхний край символов. Поэтому текст при малом Y может частично выйти за страницу. Для точной вёрстки учитывают размер шрифта и метрики либо используют textbox с известными границами.
Наложение на существующую страницу
Добавленный текст становится новым содержимым поверх или под существующим в зависимости от overlay. Белый прямоугольник не удаляет старый текст. Для необратимого удаления применяют редактирование, затем вставляют заменяющий текст отдельной операцией.
HTML и CSS через Story
Класс Story превращает HTML-фрагмент с CSS в последовательность размещаемых блоков. Он полезен для отчётов, писем, таблиц и многостраничного текста, где вручную рассчитывать перенос каждой строки неудобно. Сценарий задаёт прямоугольник кадра, вызывает place(), фиксирует draw() и создаёт следующую страницу, пока материал не закончится.
CSS управляет шрифтами, отступами, границами и таблицами, но он не повторяет браузерный движок полного профиля. Сложные современные макеты, сценарии и интерактивность не являются его целью. Разметку упрощают, а набор поддерживаемых свойств проверяют на тестовом фрагменте.
Для повторяющихся колонтитулов и нумерации Story сочетают с отдельными операциями страницы. Основной поток размещают в центральном прямоугольнике, затем добавляют заголовок, номер и служебные линии. Такой подход предотвращает пересечение содержимого с полями.
Контроль переполнения
place() сообщает, сколько содержимого поместилось и осталось ли продолжение. Цикл защищают от ситуации, когда в слишком маленький прямоугольник не помещается ни один элемент: без проверки можно создать бесконечное число пустых страниц. Если размещение не продвинулось, размеры кадра или CSS исправляют.
Шрифты в Story
Пользовательские шрифты подключают через архив шрифтов и CSS. Проверяют, что жирное и курсивное начертания действительно доступны, иначе движок подставит другой ресурс. Для архивного документа контролируют встроенность шрифтов и визуальную стабильность на другой системе.
Аннотации и комментарии
Page поддерживает подсветки, подчёркивания, зачёркивания, текстовые заметки, штампы, линии, многоугольники, прямоугольники и другие аннотации. После создания свойства меняют через set_info(), set_colors(), set_opacity() и другие методы, затем вызывают update(), чтобы записать внешний вид.
Аннотация является отдельным интерактивным объектом. Она видна в просмотрщике, но не изменяет базовый текст страницы. Это важно при согласовании: комментарий можно удалить, скрыть или распечатать без него. Если требуется необратимо удалить данные, аннотация-плашка не подходит.
При обходе page.annots() не следует менять структуру страницы внутри того же генератора. Надёжнее собрать список xref или получить следующую аннотацию заранее. После сохранения итог проверяют в нескольких просмотрщиках, потому что поддержка редких свойств и всплывающих заметок различается.

Подсветка нескольких строк
Для многострочного совпадения создают аннотацию из списка Quad. Один общий Rect закроет пустое пространство между короткими строками. Quad повторяет реальные строки и лучше выглядит на наклонном тексте.
Внешний вид и содержимое заметки
Поле content хранит текст комментария, а title может содержать имя автора. Эти данные попадают в PDF и извлекаются другим пользователем. Перед публикацией очищают служебные имена, даты и комментарии, если они не должны уходить получателю.
Необратимое удаление конфиденциальных данных
Правильное редактирование состоит из двух этапов. Сначала add_redact_annot() добавляет области, которые показывают оператору для проверки. Затем apply_redactions() удаляет перекрытое содержимое и формирует внешний вид заливки. Пока второй этап не выполнен, данные остаются в структуре документа.
Поиск по строке удобен для точного идентификатора, но не гарантирует охват всех представлений. Адрес может быть разбит на фрагменты, изображён сканом или повторён в метаданных, вложении и комментарии. Политика удаления перечисляет все каналы: текст страниц, изображения, аннотации, формы, свойства документа, вложенные файлы и скрытые слои.
После применения редактирования файл сохраняют с очисткой мусора в новый путь. Инкрементальное сохранение может оставлять старые объекты в предыдущих ревизиях, поэтому для конфиденциальной выдачи нужен полный переписывающий save с подходящим garbage. Проверка включает повторный search_for(), get_text(), анализ объектов и визуальный рендер.

Изображения и векторная графика в области
Параметры apply_redactions определяют, как обрабатывать изображения и рисунки, пересекающие область. Полное удаление части изображения может изменить больше, чем ожидается, а игнорирование оставит конфиденциальный пиксель под чёрной заливкой. Для критичных документов делают тест на копии и увеличенный контрольный рендер.
Замена удалённого текста
Redact-аннотация может содержать замещающий текст, но его размещение ограничено прямоугольником и доступными шрифтами. Для сложной замены сначала удаляют исходник, затем отдельным шагом вставляют проверенный текст с нужным шрифтом и координатами.
Интерактивные формы и виджеты
Поля формы представлены объектами Widget. Через page.widgets() получают имя, тип, текущее значение, прямоугольник, допустимые варианты и другие свойства. После присваивания field_value вызывают update(). Для флажков и переключателей важно знать экспортное значение: строка выбранного состояния может отличаться от привычного Yes.
Текстовое поле может иметь ограничение длины, многострочный режим, форматирование и JavaScript-действия. Библиотека изменяет данные поля, но не исполняет всю логику интерактивного просмотрщика. Если форма рассчитывает итог сценарием, после заполнения проверяют результат в целевом просмотрщике или самостоятельно вычисляют зависимые поля.
При создании нового Widget задают field_name, field_type, rect и свойства, затем add_widget(). Имена должны быть уникальными там, где поля независимы. Поля с одинаковым именем могут быть связанными экземплярами и менять значение совместно, что иногда полезно, а иногда приводит к неожиданному дублированию.

Внешний вид заполненного поля
Некоторые просмотрщики строят appearance-поток сами, другие показывают только уже записанный внешний вид. После update() страницу рендерят и открывают отдельным просмотрщиком. Если значение извлекается, но визуально пусто, проблема часто в appearance, шрифте или флагах поля.
Сплющивание формы
Сплющивание превращает видимое состояние полей в обычное содержимое и убирает интерактивность. Это удобно для финального архива, но лишает получателя возможности менять значения. Перед операцией сохраняют исходную заполняемую копию и проверяют отображение всех полей.
Ссылки, оглавление и переходы
get_links() возвращает прямоугольники и назначения ссылок: внешний URI, переход на страницу, файл или именованную цель. insert_link() и update_link() позволяют добавлять и менять активные области. Прямоугольник ссылки должен соответствовать надписи; слишком большой участок перекрывает соседние элементы и мешает работе.
Оглавление читается как список уровней, названий и номеров страниц. Нумерация в TOC начинается с единицы, в отличие от индекса Page. При сборке документов это различие легко даёт смещение на одну страницу. Уровни должны образовывать корректную иерархию: нельзя перескочить с первого сразу на третий без промежуточного уровня.
При удалении или перестановке страниц пересматривают назначения ссылок и оглавления. Структурная операция не всегда понимает смысл пользовательской навигации. После сборки проверяют переходы в начале, середине и конце, а также ссылки на удалённые листы.
Внешние ссылки и безопасность
URI из входного PDF считают недоверенными данными. При построении собственного интерфейса их нельзя открывать автоматически. Ссылки выводят как текст, фильтруют схемы и требуют явного действия пользователя.
Именованные цели
Некоторые документы используют именованные destinations вместо прямого номера страницы. При переносе листов между файлами такие цели могут потеряться. Для критичной навигации цели разрешают в конкретные страницы и проверяют итоговый каталог вручную.
Метаданные, вложения и служебные данные
doc.metadata содержит стандартные поля: заголовок, автор, тема, ключевые слова, создатель и производитель. set_metadata() записывает словарь, но пустая строка и отсутствие значения могут трактоваться по-разному. Для обезличивания формируют полный разрешённый набор и сохраняют новый файл с очисткой.
Метаданные XMP способны хранить больше сведений, чем обычный словарь. Если требуется строгая санитарная обработка, учитывают XML-пакет, идентификаторы документа, журнал изменений PDF и пользовательские свойства. Простое обнуление author не гарантирует, что имя нигде не осталось.
PDF может содержать вложенные файлы. Методы embfile_names(), embfile_info(), embfile_get(), embfile_add() и связанные операции позволяют перечислять и извлекать их. Входные вложения проверяют как отдельные недоверенные файлы; автоматически запускать или открывать их содержимое нельзя.

Контроль после обезличивания
После сохранения повторно читают metadata, XMP и список вложений. Дополнительно ищут известные имена в байтах и извлечённом тексте, понимая, что сжатие скрывает простую строку. Для повышенных требований применяют специализированную проверку PDF-структуры.
Идентификаторы документа
Полное сохранение может изменить идентификаторы, а инкрементальное добавляет новую ревизию. Если идентификатор используется внешней системой, изменение согласуют. Для конфиденциальной очистки приоритетом обычно является удаление старых данных, а не сохранение прежней ревизионной цепочки.
OCR для сканированных страниц
Если get_text() возвращает пустую строку, сначала убеждаются, что страница действительно состоит из изображения, а не содержит текст с проблемной кодировкой. Для изображения используется get_textpage_ocr(), который вызывает Tesseract и создаёт TextPage с распознанным слоем. Языки и обучающие данные Tesseract устанавливаются отдельно и должны быть доступны по корректному пути.
OCR значительно медленнее обычного извлечения, поэтому его запускают только для страниц без достаточного текстового слоя. Один раз созданный OCR TextPage повторно используют для get_text() и search_for(), иначе дорогое распознавание повторяется. DPI выбирают по размеру шрифта и качеству скана; слишком низкий теряет детали, слишком высокий расходует память без гарантии улучшения.
Распознанный текст содержит ошибки, особенно в таблицах, мелком шрифте, повёрнутых сканах и документах с шумом. Для числовых полей применяют допустимые форматы, контрольные суммы и сопоставление с визуальной областью. OCR нельзя считать доказательством содержания без проверки критичных данных.

Подготовка скана
До OCR оценивают поворот, контраст и наличие огромных полей. Рендер clip только рабочей области уменьшает объём, но изменяет координаты относительно полной страницы. Если потом нужны исходные координаты, преобразование сохраняют.
Смешанные страницы
На странице могут одновременно присутствовать настоящий текст и сканированный фрагмент. Полный OCR создаст дубликаты и ухудшит поиск. Лучше определить области без текстового слоя и распознавать только их либо сравнить плотность извлечённого текста с площадью страницы.
Шифрование, пароли и разрешения
При сохранении PDF можно задать алгоритм шифрования, пароль владельца, пароль пользователя и набор разрешений. Пароль пользователя открывает документ, а пароль владельца управляет изменением и печатью. Пустые или слабые пароли не дают практической защиты; управление ключами должно происходить вне исходного кода.
Разрешения PDF являются политикой для добросовестного просмотрщика, а не абсолютной криптографической границей после открытия владельцем. Сценарий должен уважать ограничения входного документа и организационные правила, даже если техническая операция возможна.
При повторном сохранении зашифрованного файла явно решают, сохранять ли исходное шифрование, удалить его или применить новое. Ошибка в параметрах может создать открытый результат. Автоматический тест закрывает файл, пытается открыть его без пароля и с ожидаемым паролем, затем проверяет доступность страниц.
Передача пароля
Пароль нельзя писать в журнал, командную строку общего сервера или сообщение исключения. Его получают из защищённого хранилища и держат в памяти минимальное время. Для пакетной обработки ошибки аутентификации отделяют от повреждения документа.
Совместимость алгоритмов
Старые просмотрщики могут не поддерживать современные варианты шифрования, а слабые устаревшие алгоритмы не подходят для защиты. Выбор делают по требованиям среды и проверяют на устройствах получателя.
Сохранение, сжатие и очистка
Полное сохранение в новый файл — наиболее предсказуемый путь. Параметр garbage удаляет недостижимые объекты и может объединять дубликаты, deflate сжимает подходящие потоки, clean упорядочивает команды содержимого. Максимальные значения не всегда дают минимальный файл и занимают больше времени, поэтому параметры измеряют на типичном наборе документов.
Инкрементальное сохранение добавляет изменения в конец исходного PDF. Оно быстрое и может сохранять подписи при допустимых изменениях, но увеличивает файл и оставляет предыдущие ревизии. Для удаления конфиденциальных данных этот режим не используют. saveIncr() допустим только для подходящего исходного файла и набора изменений.
Нельзя полноценно сохранить документ поверх того же пути обычным save, когда требуется переписать структуру. Используют временный файл в том же файловом разделе, закрывают документ, проверяют новый файл и затем атомарно заменяют исходник. Так снижается риск потерять документ при сбое или нехватке места.

Почему файл увеличился
Размер растёт из-за инкрементальных ревизий, вставленных несжатых изображений, новых шрифтов или дублирования ресурсов. Сначала сравнивают save с garbage и deflate, затем исследуют крупные xref-потоки. Простое повторное сохранение не уменьшает неэффективно закодированный растр без его перекодирования.
Проверка целостности результата
После save файл открывают новым объектом, сверяют page_count, metadata, TOC, формы и контрольные извлечения. Рендер нескольких страниц выявляет исчезнувшие шрифты и графику. Для больших пакетов сохраняют SHA-256 результата и протокол параметров.
Командная строка PyMuPDF
Команда python -m pymupdf или установленная команда pymupdf предоставляет операции для инспекции, очистки, объединения, извлечения и работы со встроенными данными. Точный набор подкоманд проверяют через pymupdf --help и справку конкретной операции, потому что параметры различаются по назначению.
CLI удобен для разовой задачи и автоматизации оболочкой: можно очистить проблемный PDF, объединить файлы или вывести сведения без написания модуля. Сложная логика — проверка координат, выбор страниц по содержимому, аудит редактирования — яснее и безопаснее в Python-коде с тестами.
Пути с пробелами заключают в кавычки, а выходной файл задают отдельно от входного. В сценарии оболочки проверяют код завершения и наличие результата. Текст, напечатанный в консоль, не заменяет проверку самого PDF.
Пакетная оболочка
Для каталога входов создают отдельную папку результатов и журнал. Ошибка одного документа не должна прерывать весь пакет без отчёта. Имена нормализуют, а существующие файлы не перезаписывают молча.
Когда перейти к API
Если команда требует нескольких проходов, условной логики или сохранения геометрии, API уменьшает число промежуточных файлов. Он также позволяет обрабатывать поток из памяти и связывать результат с базой данных.
Производительность и параллельная обработка
Рендеринг и разбор PDF выполняются быстро, но объём работы зависит от числа страниц, сложности векторной графики, количества шрифтов и DPI. Измерять нужно конкретный сценарий: простой get_text(), построение rawdict, рендер 300 dpi и OCR имеют совершенно разную стоимость.
Библиотека не поддерживает безопасное использование из нескольких потоков. Для параллельной обработки применяют multiprocessing: каждый процесс самостоятельно открывает документ и обрабатывает свой диапазон. Объекты Document и Page не передают между процессами; передают путь, номера страниц и простые настройки.
Разбиение по равному числу страниц не всегда равномерно: одна страница с большой схемой может быть тяжелее десяти текстовых. Для длинных документов создают небольшие чанки и очередь задач. Число процессов ограничивают памятью, особенно при высоком DPI и OCR.
Сбор результата по порядку
Процессы могут завершать страницы в разной последовательности. Каждый результат помечают исходным индексом и сортируют перед объединением. Для извлечения текста это список записей, для PDF-фрагментов — контролируемая вставка страниц.
Кэширование и повторный разбор
Если на странице нужны текст, поиск и таблицы, переиспользуют TextPage и полученные структуры. Если документ обрабатывается разными процессами, общего кэша объектов нет; кэшировать лучше сериализованные результаты, а не живые Page.
Низкоуровневая работа с xref
PDF состоит из объектов, связанных номерами xref. Document предоставляет методы для чтения ключей, потоков и ссылок, что позволяет диагностировать необычные файлы, находить крупные объекты и менять свойства, недоступные высокоуровневому API. Такой уровень требует знания спецификации PDF: неверное значение делает файл нечитаемым.
xref_length показывает размер таблицы объектов, xref_object — текстовое представление объекта, xref_stream — декодированный поток. Перед изменением сохраняют исходный объект и работают на копии. После изменения выполняют полное сохранение и повторную проверку.
Низкоуровневый доступ не используют там, где есть Document, Page, Annot или Widget API. Высокоуровневые методы поддерживают связи и внешний вид, тогда как ручная запись ключа может оставить противоречивую структуру.
Поиск крупных потоков
Для анализа размера перебирают xref, получают длину потоков и сортируют. Крупнейшими часто оказываются изображения, встроенные шрифты и содержимое сканов. Удалять объект только по размеру нельзя: сначала выясняют, где он используется.
Диагностика повреждения
Если предупреждение указывает на объект, его содержимое изучают через xref. Исправление вручную — крайняя мера. Часто достаточно открыть и сохранить файл с очисткой, затем сравнить видимые страницы.
Типовые ошибки и их устранение
Сообщение orphaned object: parent is None означает, что Page, Annot или Widget больше не связан с действующим документом. Причина — закрытие документа либо структурная операция. Решение — держать Document открытым и заново получить страницу и дочерний объект после изменения.
Пустой текст при видимой странице обычно указывает на скан, векторные контуры вместо символов или шрифт без корректного Unicode-сопоставления. Сначала проверяют get_images(), get_drawings() и rawdict. OCR применяют к растру; векторный текст без Unicode может потребовать специализированного восстановления или другого источника.
Ошибка сохранения в исходный путь возникает, когда обычный save пытается переписать открытый файл. Сохраняют во временный путь либо используют инкрементальный режим только там, где он допустим. После успешной проверки временный файл заменяет исходный.
Неверные цвета или чёрный фон на изображении часто связаны с альфа-каналом и способом преобразования Pixmap. Для обычного PNG создают RGB с alpha=False. CMYK перед передачей в систему, ожидающую RGB, преобразуют в подходящее цветовое пространство.
Слишком много памяти
Уменьшают DPI, рендерят clip, обрабатывают страницы по одной и освобождают Pixmap. В multiprocessing сокращают число процессов. Rawdict с посимвольными данными заменяют words или dict, если точность символов не требуется.
Предупреждения без исключения
MuPDF может записать предупреждение и продолжить работу. Их нельзя терять в серверном журнале. После предупреждения документ сохраняют в новый файл и проверяют контрольные страницы, потому что восстановление могло изменить структуру.
Текст есть, но поиск не находит
Причиной бывают перенос, лигатура, неразрывный пробел, нестандартный регистр или разбиение на spans. Проверяют words, нормализуют строку и при необходимости собирают совпадение из последовательности слов по координатам.
Практический сценарий: извлечение реквизитов
Для счетов и актов сначала определяют семейства шаблонов по размеру страницы, устойчивым заголовкам и расположению таблицы. Затем извлекают words с sort=True, находят метки Номер, Дата, Итого и выбирают ближайшее значение справа или ниже в ограниченном прямоугольнике. Каждый результат сохраняют вместе с bbox и номером страницы.
Табличные позиции получают find_tables(), но итоговые суммы сверяют с арифметикой строк. Валюту и десятичный разделитель нормализуют после извлечения, сохраняя исходную строку. Если уверенность низкая, формируют вырезку области для ручной проверки.
Сканированные счета направляют в OCR только после проверки отсутствия текстового слоя. Для каждого поля задают формат: дата, идентификатор, сумма, номер договора. Значение, не прошедшее формат и контроль, не подставляют молча — оно попадает в очередь проверки.
Аудит результата
Запись результата включает хэш PDF, номер страницы, текст, координаты, способ получения и версию конфигурации шаблона. Это позволяет доказать, откуда взялось значение, и повторить извлечение после изменения правил.
Практический сценарий: безопасная публикация
Сначала создают копию документа и перечень запрещённых данных: имена, контакты, номера, QR-коды, фотографии, комментарии, метаданные и вложения. Текстовые значения ищут search_for() и алгоритмом по words, визуальные области задают вручную или моделью разметки. Все области сохраняют в журнал до изменения PDF.
На этапе предпросмотра добавляют redact-аннотации и рендерят страницы с рамками для оператора. После подтверждения вызывают apply_redactions(), очищают метаданные и вложения, сохраняют полным способом с garbage и deflate. Исходник остаётся в защищённом хранилище, а опубликованный файл получает новый идентификатор.
Финальная проверка повторяет поиск запрещённых строк, извлекает весь текст, перечисляет изображения, формы и аннотации, а также создаёт рендер высокого разрешения. Отдельный человек или автоматическое правило сравнивает ожидаемое число удалений с фактическим.
Почему чёрная плашка недостаточна
Нарисованный прямоугольник остаётся отдельным объектом. Текст под ним можно извлечь или удалить плашку. Только apply_redactions с последующим полным сохранением предназначен для удаления перекрытого содержимого.
Практический сценарий: сервис миниатюр
Сервис принимает файл, проверяет размер и тип, открывает документ и рендерит первую страницу с фиксированным DPI и alpha=False. Для длинных документов миниатюры создаются по запросу либо в ограниченном числе процессов. Результат сохраняют в PNG или JPEG в зависимости от требований к прозрачности и фотографиям.
Чтобы одинаковый PDF не обрабатывался повторно, ключ кэша строят из SHA-256 файла, номера страницы, DPI, clip и цветового пространства. Изменение любого параметра создаёт другой ключ. Ошибки рендера не кэшируют как успешный результат.
Для защиты ресурсов вводят максимальное число страниц, площадь изображения и тайм-аут задачи. PDF с огромной страницей или сложной векторной схемой может потребовать значительно больше памяти, чем следует из размера файла.
Проверка ориентации
Миниатюра должна учитывать rotation страницы. Если внешняя система передаёт собственный crop, его преобразуют через матрицы страницы. Контрольный тест включает листы 0, 90, 180 и 270 градусов.
Практический сценарий: заполнение формы
Сценарий перечисляет все widgets и строит словарь по field_name. Перед заполнением он сравнивает ожидаемые поля с фактическими: отсутствие обязательного имени считается ошибкой шаблона, а неизвестное поле фиксируется в журнале. Для choice-полей значение проверяется по choice_values.
После присваивания вызывается update(), затем документ сохраняется в новый файл. Рендер страниц с формами сравнивается с эталоном: видны ли длинные строки, отмечены ли флажки, не обрезаны ли даты. При необходимости размер шрифта поля и внешний вид настраиваются отдельно.
Если получателю нужна неизменяемая копия, создают сплющенный вариант после проверки. Заполняемый оригинал и данные ввода сохраняют отдельно. Сплющивание нельзя использовать как замену контролю содержимого: ошибочное значение станет частью страницы и исправлять его будет сложнее.
Связанные поля
Одинаковое имя на нескольких страницах может означать намеренно синхронизированные поля. Сценарий должен обнаружить все экземпляры и проверить ожидаемое поведение, а не обновить только первый Widget.
Практический сценарий: сборка отчёта
Исходные данные подготавливают как HTML с простой семантической структурой: заголовки, абзацы, таблицы и списки. Story размещает поток в рамке страницы, а отдельные операции добавляют фирменный заголовок, номер страницы и служебные линии. Изображения заранее приводят к разумному размеру, чтобы не раздувать PDF.
Цикл размещения создаёт новую страницу только когда предыдущая заполнена и Story сообщает о продолжении. Для таблицы проверяют разрыв строк и повтор заголовка. Если один элемент больше доступной рамки, макет должен изменить его размер или вывести понятную ошибку, а не создавать пустые страницы.
После генерации get_text() используется как дымовой тест: в документе должны присутствовать ключевые заголовки и итоговые значения. Рендер первой, средней и последней страницы проверяет поля, переносы и шрифты.
Доступность и порядок чтения
Визуально корректный PDF не обязательно имеет удобную структурную навигацию. Story помогает получить последовательный текстовый поток, но для требований доступности могут понадобиться дополнительные теги и специализированная проверка. Это учитывают до выбора формата отчёта.
Сравнение PyMuPDF с аналогами
Выбор зависит не от абстрактного числа функций, а от точки входа. PyMuPDF объединяет быстрый рендер, геометрию текста и широкий набор изменений в одном API. PDF Commander удобнее, когда документ редактирует человек и результат нужно получить через визуальные команды. pypdf подходит для структурных операций без движка рендера, а pdfplumber и pdfminer.six сильны в исследовании текстового слоя. pypdfium2 выбирают, когда приоритетом является PDFium и растеризация.
Практический выбор
Для пакетного конвейера, где нужно извлекать координаты, создавать изображения, ставить аннотации и сохранять изменённые PDF, рационален PyMuPDF. Для ручной правки без программирования — PDF Commander. Для простого объединения и метаданных — pypdf. Для сложных таблиц и визуальной диагностики — pdfplumber. Для глубокого разбора текстовой компоновки — pdfminer.six. Для приложения вокруг PDFium — pypdfium2.
| Программа | Лучше подходит для | Главное ограничение |
|---|---|---|
| PyMuPDF | Быстрого программного извлечения, рендера и изменения PDF | Требует Python-кода и знания структуры PDF |
| PDF Commander | Ручного редактирования, сборки и подписания документов | Не предназначен как Python-библиотека для серверных конвейеров |
| pypdf | Операций со страницами, метаданными, формами и шифрованием на чистом Python | Не выполняет полноценный рендер страниц |
| pdfplumber | Исследования текста, символов, линий и таблиц с визуальной отладкой | Редактирование и создание PDF не являются основной задачей |
| pdfminer.six | Подробного анализа текстового слоя и компоновки | Сложнее применять для рендера и модификации документов |
| pypdfium2 | Быстрого рендера и низкоуровневого доступа к PDFium | Набор высокоуровневых средств редактирования уже |
Совместимость и требования к окружению
Для работы нужен поддерживаемый CPython и подходящий пакет для архитектуры системы. Готовые сборки предназначены для современных Windows, macOS и Linux. На сервере без графической оболочки рендер и извлечение выполняются без открытия окна; важны файловые права, память и шрифты, которые использует сценарий при создании текста.
OCR не появляется автоматически вместе с библиотекой: требуется установленный Tesseract и языковые данные. Для кириллицы нужен соответствующий языковой пакет, для смешанных документов — комбинация языков. Путь к данным проверяют в окружении запуска сервиса, а не только в интерактивной сессии администратора.
Функции чтения офисных файлов не следует приписывать основному пакету: для таких форматов существуют отдельные компоненты. Надёжный конвейер явно ограничивает входные расширения и не пытается открыть DOCX как обычный PDF.
Контейнеры и минимальные образы
В контейнере должны присутствовать системные библиотеки, требуемые колесом, а также шрифты для генерируемого текста и Tesseract для OCR. После сборки запускают smoke-тест: импорт, открытие PDF, извлечение строки, рендер страницы и сохранение копии.
Архитектура и Python
Разрядность интерпретатора должна совпадать с колесом. Ошибки загрузки нативного модуля часто возникают из-за несовместимого Python, старого pip или пакета другой архитектуры. Проверка platform.machine() и sys.version быстрее повторной переустановки вслепую.
Лицензирование и внедрение
Пакет распространяется по AGPL, а для проектов, которые не могут выполнять требования этой лицензии, предлагается коммерческое лицензирование. Перед включением в закрытый продукт условия оценивает специалист по лицензиям. Техническая доступность пакета из публичного репозитория не отменяет обязательств по распространению и взаимодействию с пользователями.
Внутренний прототип, серверный сервис, поставляемое приложение и библиотека, передаваемая заказчику, создают разные сценарии соблюдения условий. Решение фиксируют до архитектурной интеграции, чтобы позднее не заменять PDF-движок в готовой системе.
Помимо лицензии библиотеки учитывают шрифты, Tesseract-модели и сторонние данные. Встраивание файла шрифта в PDF является отдельным видом использования; не каждый шрифт разрешает свободное распространение.
Техническая изоляция
Полезно сосредоточить обращения к библиотеке в одном модуле с собственными интерфейсами и тестами. Это упрощает обновление, аудит лицензий и возможную замену реализации без переписывания бизнес-логики.
Контроль качества перед выдачей результата
Проверка PDF охватывает структуру и внешний вид. Структурные тесты открывают файл заново, сверяют число страниц, оглавление, формы, аннотации и метаданные, ищут ключевые строки и убеждаются в отсутствии удалённых данных. Визуальные тесты рендерят контрольные страницы и сравнивают размеры, поля, шрифты и расположение объектов.
Для операций с координатами сохраняют изображения до и после с нанесёнными рамками. Это позволяет быстро увидеть смещение из-за поворота, CropBox или неверного масштаба. Для таблиц хранят эталонное число строк и столбцов, а для форм — список полей и ожидаемые значения.
Производственный журнал не должен содержать конфиденциальный текст целиком. Достаточно хэша документа, номера страницы, типа операции, количества объектов и обезличенного идентификатора правила. Подробный диагностический пакет создают только в защищённом контуре.
Минимальный набор регрессионных PDF
Нужны цифровой текстовый документ, скан, смешанная страница, таблица с сеткой и без неё, форма, файл с аннотациями, зашифрованный PDF, повёрнутые страницы, нестандартный шрифт и намеренно повреждённый пример. Каждый тест проверяет конкретный риск, а не просто успешное открытие.
Завершение обработки
Документ считается готовым не после вызова save, а после повторного открытия и проверки. Этот шаг обнаруживает ошибки путей, обрезанный текст, неверный пароль, пустые поля и неудачное редактирование до того, как файл попадёт пользователю.
Отладка координат на реальном документе
Когда рамка не совпадает с текстом, выводят page.rect, rotation, CropBox и координаты первого найденного слова. Затем рендерят страницу при известной Matrix и умножают координаты на тот же масштаб. Если изображение дополнительно уменьшалось средствами интерфейса, вводят второй коэффициент отображения. Смешивание этих двух масштабов — частая причина смещения.
Для проверки создают копию изображения и рисуют на ней прямоугольники найденных слов. Если рамки верны на исходном рендере, ошибка находится в интерфейсе просмотра; если уже там неверны, проверяют поворот, clip и источник координат. Такой диагностический кадр быстрее чтения десятков чисел в журнале.
Координаты, полученные из OCR-вырезки, относятся к вырезке, а не ко всей странице. Для возврата в исходную систему к ним добавляют смещение clip и учитывают масштаб. Для повернутой области операция усложняется матрицей, поэтому преобразование оформляют отдельной тестируемой функцией.
Контрольный крест и сетка
Для сложного случая на тестовой копии рисуют сетку через каждые 50 пунктов и подписывают значения X и Y. По ней сразу видно, какая система координат использована и был ли применён поворот. После диагностики эти элементы не переносят в результат.
Обработка очень больших документов
Не следует извлекать rawdict всех страниц в один список. Страницы обрабатывают потоково, результат записывают порциями в базу или JSON Lines, а тяжёлые изображения сразу сохраняют и освобождают. Для возобновления после сбоя фиксируют последнюю успешно обработанную страницу и хэш входа.
Перед стартом оценивают page_count, размеры страниц и наличие сканов. Порог максимальной площади защищает от листов нестандартного формата, которые при высоком DPI создают гигантские Pixmap. Для сервисов задают лимиты времени и памяти на отдельный документ.
При разборе тысяч страниц полезно разделять быстрый предварительный проход и дорогую обработку. Первый собирает размер, наличие текста и изображения; второй запускает таблицы, OCR или высокий DPI только там, где это действительно нужно. Такой фильтр уменьшает время и число ложных операций.
Промежуточные результаты
Временные файлы пишут в каталог с достаточным свободным местом и удаляют после успешного объединения. Каждый фрагмент получает номер диапазона и хэш, чтобы при повторном запуске не спутать результаты от другой версии входного PDF.
Работа с цветом и прозрачностью
Pixmap может быть серым, RGB или CMYK. Перед передачей в Pillow, OpenCV или систему распознавания каналы приводят к ожидаемому формату. Неправильная интерпретация CMYK как RGB даёт инвертированные или грязные цвета. Альфа-канал либо сохраняют и корректно компонуют, либо убирают на определённом фоне.
При сравнении рендеров допустимы небольшие различия сглаживания, но не пропавшие объекты и заметный сдвиг. Визуальный регрессионный тест использует допуск по пикселям и отдельно контролирует геометрию крупных областей.
Если прозрачная страница сохраняется как JPEG, фон нужно задать заранее, потому что формат не поддерживает альфу. Для PNG решают, нужен ли прозрачный фон потребителю. Лишний альфа-канал увеличивает память и иногда создаёт чёрный фон в программах, которые интерпретируют прозрачность неверно.
Цветные аннотации
Цвета аннотаций задаются в диапазоне от нуля до единицы и могут включать обводку и заливку. После set_colors() вызывают update(). Контрольный рендер нужен, потому что прозрачность и режим наложения меняют визуальный оттенок поверх цветного фона.
Подготовка данных для поиска и индекса
Для поискового индекса сохраняют текст по страницам, границы блоков и ссылку на исходный документ. Нормализованная версия нужна для поиска, а исходная — для показа фрагмента. Если хранить только сплошную строку, будет трудно подсветить совпадение в просмотрщике.
Индексирование удаляет повторяющиеся колонтитулы, но не должно терять номера разделов и таблиц. Правило проверяют статистикой: какие строки отбрасываются и на скольких страницах они встречаются. Ошибочное правило может удалить название организации со всех документов.
Для ответа с контекстом слова объединяют в абзацы по блокам, сохраняя номера страниц и bbox. При совпадении поиск возвращает не только текст, но и координаты, по которым интерфейс показывает страницу и выделяет источник. Это делает результат проверяемым.
Нормализация без потери оригинала
Регистр, пробелы и Unicode нормализуют в отдельном поле. Оригинальный текст не перезаписывают, иначе пользователь увидит изменённую пунктуацию и не сможет сопоставить фрагмент с PDF.
Встраивание в веб-службу
Загрузку принимают во временное хранилище с непредсказуемым именем, ограничивают размер и не доверяют расширению. Обработку выполняют в отдельном процессе с лимитами ресурсов. Результат не возвращают, пока он не открыт повторно и не прошёл проверку ожидаемого типа.
Объект Document не держат глобально между запросами и не используют из нескольких потоков. Каждый рабочий процесс открывает собственный экземпляр. Временные файлы удаляют в блоке finally, а журнал связывает запрос с хэшем, не раскрывая содержимое.
Пользовательские параметры clip, DPI и диапазона страниц валидируют до запуска. Отрицательные номера, прямоугольник нулевой площади и огромный DPI отклоняют понятной ошибкой. Выходные имена формирует сервер, чтобы путь не вышел за разрешённый каталог.
Изоляция недоверенного PDF
Даже устойчивый парсер обрабатывает сложный бинарный формат, поэтому сервис запускают с минимальными правами, без доступа к секретам и с ограниченной файловой системой. Ошибка документа должна завершить только его задачу, а не весь рабочий процесс.
Изменение размеров и обрезка страниц
MediaBox задаёт физический размер, CropBox — видимую область. Изменение одного прямоугольника не обязательно масштабирует содержимое: оно может лишь скрыть края или открыть дополнительную область. Для реального масштабирования страницу помещают в новую через show_pdf_page() с рассчитанной матрицей.
Перед массовой обрезкой анализируют объекты у краёв: номер страницы, подпись и метки печати могут оказаться за пределами нового CropBox. Контрольный рендер включает страницы с максимальным заполнением полей.
При приведении разных страниц к одному формату выбирают правило вписывания: сохранить пропорции с полями, заполнить лист с обрезкой или растянуть. Растяжение искажает текст и графику, поэтому обычно применяют пропорциональное масштабирование и центрирование.
Пересчёт ссылок и виджетов
Изменение коробок может повлиять на положение активных областей, если содержимое реально переносится на новую страницу. При show_pdf_page() исходные интерактивные формы и ссылки не обязательно становятся полноценными объектами нового листа, поэтому навигацию и поля проверяют отдельно.