Itinai.com it company office background blured chaos 50 v 37924f9a 5cdc 441e b9ab 1def82065f09 1

Как за минуты превратить скан в поисковый PDF/A с OCRmyPDF

Itinai.com it company office background blured chaos 50 v 37924f9a 5cdc 441e b9ab 1def82065f09 1

Почему ваш скрипт с OCRmyPDF падает уже на старте?

Вы, конечно, не первый, кто попытался «переименовать» сканированную кучу PDF в удобные для поиска документы. Но почему же каждый раз возникает «ImportError: Pillow is incompatible» или «MissingDependencyError»? Давайте разберёмся, какие подводные камни таятся в вашем коде и как их победить без бесконечных переустановок.

Краткий разбор проблемного участка

В начале скрипта происходит «чистка» импортов:

  • _purge() удаляет модули PIL и ocrmypdf из sys.modules. Это выглядит как попытка «обновить» их «на лету», но в реальности только ломает кеш и приводит к повторным импортам с несовместимыми версиями.
  • Дальше _load_ocrmypdf() сразу после _purge() пытается импортировать ocrmypdf. Если в системе уже установлен Pillow другой версии, импорт завершается ошибкой, которую скрипт пытается «исцелить» распечаткой сообщения о переустановке.
  • Проблема в том, что сообщение «Repairing an incompatible Pillow…» выводится, но процесс переустановки не происходит автоматически – пользователь остаётся с тем же багом.

Что делает остальной код?

Основная часть – это набор вспомогательных функций для генерации «сканированных» PDF и запуска OCR:

  • render_page() рисует текст на изображении, добавляет шум и наклон.
  • build_scanned_pdf() собирает такие изображения в PDF‑файл.
  • do_ocr() обёртка над ocrmypdf.ocr(), отключающая прогресс‑бар и измеряющая время.

Всё это работает, пока ocrmypdf успешно импортирован и его зависимости (Pillow, img2pdf, pdfminer.six и пр.) удовлетворяют требуемым версиям.

Как избавиться от «постоянных переустановок»?

Самый надёжный путь – фиксировать версии зависимостей и управлять ими через виртуальное окружение.

  • Создайте venv или используйте conda‑окружение.
  • Запишите точные версии в requirements.txt:
ocrmypdf==15.3.0
pillow==10.2.0
img2pdf==0.4.4
pdfminer.six==20231113
  • Установите их одной командой: pip install -r requirements.txt.
  • Уберите функцию _purge() – она лишь усложняет жизнь.
  • Импортируйте ocrmypdf единожды в начале скрипта.

Пример «чистого» начала скрипта

Вот как может выглядеть стартовый блок без лишних трюков:

import sys
import time
import re
import os
from pathlib import Path
import textwrap

import ocrmypdf from ocrmypdf.exceptions import ( ExitCode, PriorOcrFoundError, EncryptedPdfError, MissingDependencyError, TaggedPDFError, DigitalSignatureError, DpiError, InputFileError, UnsupportedImageFormatError, ) import img2pdf from PIL import Image, ImageDraw, ImageFont, ImageFilter

Теперь ваш скрипт будет падать только в случае реальной ошибки (например, повреждённый PDF), а не из‑за «плохой» версии Pillow.

Обработка типичных ошибок OCRmyPDF

Когда всё уже запущено, полезно отлавливать ошибки и давать пользователю понятные рекомендации:

  • MissingDependencyError – проверьте, что ghostscript и tesseract установлены в системе.
  • EncryptedPdfError – PDF защищён паролем. Добавьте параметр owner_password в вызов ocrmypdf.ocr().
  • PriorOcrFoundError – в документе уже есть слой текста. Включите force_ocr=True или используйте --skip-text.
  • DpiError – слишком низкое разрешение. Установите --output-type pdfa и --image-dpi 300.

Полный рабочий пример функции do_ocr

def do_ocr(input_file: Path, output_file: Path, **kwargs):
    """Запуск OCRmyPDF с таймингом и обработкой типовых исключений."""
    kwargs.setdefault("progress_bar", False)
    start = time.perf_counter()
    try:
        rc = ocrmypdf.ocr(str(input_file), str(output_file), **kwargs)
        elapsed = time.perf_counter() - start
        print(f"OCR завершён за {elapsed:.2f} с, код возврата {rc}.")
        return rc
    except MissingDependencyError as e:
        raise SystemExit(f"Недостаёт зависимости: {e}")
    except (EncryptedPdfError, PriorOcrFoundError) as e:
        raise SystemExit(f"PDF не может быть обработан: {e}")

Таким образом, ваш скрипт будет «говорить» на человеческом языке, а не бросать стек‑трейсы, которые пугают даже опытных разработчиков.

Где искать ответы и свежие версии?

Итого: что нужно сделать прямо сейчас

  • Создайте виртуальное окружение.
  • Зафиксируйте версии зависимостей в requirements.txt.
  • Уберите _purge() и «принудительный» импорт.
  • Обновите импорт в начале скрипта и добавьте лёгкую обработку ошибок.
  • Проверьте наличие системных утилит ghostscript и tesseract.

После этих шагов ваш OCR‑pipeline будет работать как часы, а вы сможете спокойно отдыхать, зная, что «плохой Pillow» больше не будет вас мучить.

Запустите свой ИИ проект бесплатно

ИИ-агенты искусственный интеллект онлайн для бизнеса

Лучший ИИ онлайн