ГлавнаяБлогРедактирование PDF на Python: как заменить текст без артефактов
Python

Редактирование PDF на Python: как заменить текст без артефактов

Заменить текст в PDF на Python сложно: шрифты, кернинг и подмножества. Узнайте, как восстановить параметры и избежать артефактов. Читайте и применяйте!

Al
Редакция Algolitalgolit.ru
7 мин чтения23 августа 2026 г.

Почему замена текста в PDF — это боль

Представьте: вы открываете PDF, находите слово, которое нужно заменить, и вносите правку. Кажется, что это просто? Я потратил месяцы на создание PDF-редактора, и именно эта функция — «заменить слово, не трогая остальное» — съела больше всего времени. В этой статье я расскажу, почему это так сложно, и как избежать типичных ошибок. Вы узнаете, как работает текст в PDF, какие подводные камни ждут при замене, и получите практические советы для своего проекта.

PDF не хранит текст — он хранит команды рисования

Первое, что нужно понять: PDF не хранит текст как строки. Внутри файла — инструкции для отрисовки. Одна строка текста выглядит примерно так:

BT
/F1
11
Tf
72
700
Td
[
(W)
-30
(e)
15
(l)
-20
(come)
]
TJ
ET

Массив TJ — это визуальное слово, разбитое на фрагменты с кернингом. В файле нет строки «Welcome», нет понятия абзаца или строки. Всё, что человек видит как структуру, — результат интерпретации.

Поэтому «найти и заменить» — это не строковая операция. Это: восстановить логический текст из позиционированных глифов, найти цель, вычислить, какие операции рисования создали эти глифы, удалить их и нарисовать новые так, чтобы выглядело естественно.

Четыре параметра, которые нужно восстановить

Чтобы замена была незаметной, нужны оригинальный шрифт, размер, базовая линия и цвет. Ни один из них не доступен напрямую.

Размер — не всегда число после Tf

Размер не просто число после Tf. Текстовая матрица может масштабировать его. Например, заголовок с Tf 1 внутри матрицы, масштабированной на 24, отображается как 24pt. Если читать только Tf, получите 1.

Базовая линия — критична

Базовая линия важнее, чем кажется. Если она на пару пунктов выше, глаз сразу заметит, даже если шрифт и размер идеальны.

Цвет — проблема сканов

С цветом нужно быть осторожным в сканах. Если взять цвет фона страницы и закрасить им, на кремовой бумаге получатся белые блоки.

В итоге я оценивал параметры по соседним строкам: взвешенная медиана размера, шрифта и базовой линии. И использовал оценку только тогда, когда точное значение не удавалось сопоставить. Именно в этом запасном пути жили почти все баги.

Баг, который научил меня больше всего

Замены в научных статьях выходили в неправильном шрифте: лёгкий sans-serif вместо serif. Любой читатель заметил бы, но я не мог воспроизвести.

Я создавал тестовые PDF, которые, как я был уверен, повторяют проблему: встроенные шрифты, subset, жирные заголовки. Все проходили. Я «исправил» баг три раза, но он продолжал проявляться на реальных документах.

В конце концов я перестал генерировать тестовые файлы и скачал реальную статью с arXiv. Она падала сразу, каждый раз. Причина — одна строка:

let serif = low.contains("times") || low.contains("roman") || ...

LaTeX использует Times-клон NimbusRomNo9L. В нём есть «Rom», но нет «roman». Поэтому шрифт классифицировался как sans-serif и заменялся на Helvetica. У Computer Modern та же проблема: CMR10 и CMBX12 не содержат слова «roman».

То же предположение о названии сломало определение жирности. Nimbus называет жирное начертание -Medi, а не -Bold, поэтому заголовки выходили обычным весом.

Два сравнения строк — и они проявились только на документах, которые мой генератор не мог создать. Мои тестовые файлы создавались библиотекой, которая выдаёт чистые TrueType с аккуратными именами. Реальные документы — из LaTeX, Word, двадцатилетних сканеров — полны аббревиатур, которые никто не документирует.

Подмножества шрифтов и неизбежность запасного плана

PDF обычно встраивает только подмножество каждого шрифта — лишь те глифы, которые уже использованы. Это позволяет держать размер файла разумным, но это ловушка. Если в оригинальном тексте не было буквы «z», во встроенном шрифте её нет. Замените слово на то, где нужна «z», — и вы не сможете нарисовать её шрифтом документа.

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

Что реально помогло

Начните с существующего текста. Позволить пользователю нарисовать прямоугольник и вписать текст — значит гадать о шрифте, размере и базовой линии по прямоугольнику. Если сначала определить текстовые блоки и дать выбрать один, параметры будут известны, а не выведены. Тот же интерфейс, но гораздо меньше догадок.

Тестируйте на документах, которые вы не создавали. Сгенерированные тестовые файлы разделяют ваши предположения — именно поэтому они бесполезны для поиска таких багов. Одна реальная статья с arXiv нашла больше, чем неделя синтетических случаев.

Измеряйте результат, а не процесс. «Правка применилась» — не вопрос. Вопрос — правильного ли размера замена, на правильной ли базовой линии и не пересекается ли с соседями. Это значит рендерить результат и сравнивать.

Попробуйте сломать

Редактор доступен на marqpdf.com. Откройте PDF — он обведёт каждую строку; кликните и введите текст или скажите, что изменить.

Если у вас есть PDF, который его ломает — необычный шрифт, государственная форма, многоколоночный макет, что-то, созданное неизвестным ПО, — я буду рад увидеть. Такие документы ценнее любых тестовых файлов, которые я могу написать.

Что делать прямо сейчас

Не пытайтесь писать замену текста в PDF с нуля. Изучите, как PDF хранит текст, восстановите параметры из соседних строк, тестируйте на реальных документах. И помните: если что-то выглядит просто, скорее всего, вы не знаете всех деталей.

#PDF#Python#обработка текста#шрифты#редактирование
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →