Files
hand-writter/README.md
T
second_constantine 9e81d7a3e0 handwrite.py: рукописный рендер кириллицы синими чернилами
CLI-утилита (Pillow) для превращения текста в картинку рукописного текста. Полная поддержка кириллицы, синие чернила с имитацией письма ручкой (дрейф давления, полупрозрачность, неровный край), корректное выравнивание (б/й/н на baseline, р/у/д с хвостами, точки внизу, спецсимволы), перенос по словам + сохранение переносов строк, тетрадная бумага, --list-fonts. run.sh: команды-обёртки (init/upd/render/lined/big/calm/plain/poetry/render-file/render-stdin/list-fonts/examples). Документация: README.md, AGENTS.md. Примеры в examples/.
2026-08-22 15:12:01 +03:00

8.9 KiB
Raw Blame History

handwrite.py

Python-скрипт, превращающий текст в картинку рукописного текста с поддержкой кириллицы (полный русский алфавит, включая Ё, щ, ъ, э, ю, я). Чернила — синие, с имитацией письма ручкой.

Возможности

  • 🖋️ Синие чернила «как рукой»: имитация письма ручкой — дрейф «давления» (коррелированные тёмные/светлые участки), полупрозрачные чернила, неровный край мазка
  • Полная поддержка кириллицы (автоподбор рукописного шрифта с проверкой наличия всех глифов; приоритет — Marker Felt)
  • 📐 Корректное выравнивание: обычные буквы (а, о, н, б, й) на одной базовой линии, буквы с нижними выносными (р, у, д, ц, щ) — с хвостами ниже, точки/запятые — внизу строки, спецсимволы ($ ~ % @ # & …) — по дизайну шрифта
  • 📝 Перенос по словам + сохранение \n из входного файла/STDIN
  • 📓 «Тетрадная» линейная бумага (--lined)
  • 🎨 Настройка цвета чернил/бумаги/линий, размера шрифта, полей
  • 📥 Ввод: аргументом, из файла (-i, с переносами строк), через STDIN
  • 🔒 Воспроизводимый результат через --seed

Установка

pip install -r requirements.txt   # нужна только Pillow

или через обёртку (создаст venv):

./run.sh init

Быстрый старт

# текст аргументом
python3 handwrite.py "Привет, мир!" -o hello.png

# тетрадная бумага
python3 handwrite.py "Привет, мир!" -o hello.png --lined

# из файла с переносами строк (каждая строка файла → строка на картинке)
python3 handwrite.py -i text.txt -o letter.png --lined

# через STDIN
echo "Мама мыла раму" | python3 handwrite.py -o out.png

Параметры

Параметр По умолчанию Описание
text Текст для рендера (позиционный).
-i, --input Файл с текстом (UTF-8); переносы строк сохраняются. - = STDIN, иначе при отсутствии текста — STDIN.
-o, --output handwriting.png Выходной PNG.
--font авто Путь к шрифту (path или path:index в .ttc). Иначе авто-подбор рукописного с кириллицей.
--font-size 44 Размер шрифта (pt).
--line-spacing 1.6 Множитель межстрочного интервала.
--margin 64 Поля вокруг текста (px).
--chars-per-line 48 Примерная ширина строки в символах для переноса.
--ink #1a3b8c Цвет чернил (#RRGGBB). По умолчанию — синий.
--paper #ffffff Цвет бумаги (#RRGGBB).
--lined выкл. Рисовать «тетрадные» линии.
--lined-color #cfe8ff Цвет линий бумаги.
--jitter 1.0 Сила «рукописного» дрожания (0 — ровный текст).
--no-rotate-lines выкл. Отключить лёгкий поворот строк.
--seed случайный Зерно ГПСЧ для воспроизводимости.

Примеры использования

# крупный текст на тёплой бумаге
python3 handwrite.py "Стихи на полях" -o poem.png --font-size 56 --paper "#fdf6e3" --lined

# «спокойный» почерк — меньше колебаний давления, фиксированный seed
python3 handwrite.py "Ровный аккуратный текст" -o neat.png --jitter 0.3 --seed 42

# полностью ровный текст (без дрожания и поворота)
python3 handwrite.py "Как печатный" -o plain.png --jitter 0 --no-rotate-lines

# другой синий оттенок чернил
python3 handwrite.py "Глубокий синий" -o deep.png --ink "#0f2d78"

# широкий формат (длинные строки)
python3 handwrite.py -i long_text.txt -o wide.png --chars-per-line 80 --margin 40

# другой рукописный шрифт (Snell Roundhand)
python3 handwrite.py "Текст" --font "/System/Library/Fonts/Supplemental/SnellRoundhand.ttc:0"

# многострочный файл через STDIN
cat text.txt | python3 handwrite.py -o out.png --lined

# тёмная бумага, светлые чернила (например, для презентации)
python3 handwrite.py "Белым по тёмному" -o dark.png --ink "#cfe8ff" --paper "#1a2238"

Команды run.sh

Удобные обёртки для типовых задач (вывод — в out/):

Команда Описание
./run.sh init Создать venv и установить зависимости
./run.sh upd Обновить зависимости
./run.sh render "текст" Рендер текста → out/handwriting.png
./run.sh lined "текст" Рендер на тетрадной бумаге → out/handwriting.png
./run.sh big "текст" Крупный шрифт (64pt) на тёплой бумаге
./run.sh calm "текст" «Спокойный» почерк (jitter 0.3, seed 42)
./run.sh plain "текст" Ровный текст (без дрожания/поворота)
./run.sh render-file file Рендер файла (с переносами строк)
./run.sh poetry file Многострочный файл → тетрадь, крупный шрифт
./run.sh render-stdin Чтение из STDIN (echo "..." | ./run.sh render-stdin)
./run.sh list-fonts Показать доступные рукописные шрифты с кириллицей
./run.sh examples Перегенерировать примеры в examples/

Доп. опции handwrite.py передаются после -- (или просто в конце):

./run.sh render "Текст" -- --jitter 0.4 --seed 7
./run.sh render-file text.txt --chars-per-line 60
./run.sh lined "Текст" -- --ink "#0f2d78"

Примеры

examples/
├── blue_pen.png        # синий текст «от руки»
├── blue_pen_lined.png  # синий текст на тетради
├── multiline.png       # из файла с переносами строк
└── sample_input.txt    # пример входного файла

Перегенерировать: ./run.sh examples.

Подбор шрифта

Скрипт автоматически ищет рукописный шрифт с полным покрытием кириллицы:

  1. Проверяет приоритетные системные шрифты (Marker Felt, затем Snell Roundhand).
  2. Сканирует системные каталоги, отбирая «рукописные» имена и проверяя все глифы кириллицы.
  3. В крайнем случае берёт любой шрифт с поддержкой кириллицы.

Проверка глифов — без сторонних библиотек (только Pillow): каждый символ рендерится и сравнивается с формой notdef-глифа. Узкие буквы (например «г») неотличимы от notdef по ширине, поэтому сравнение делается по форме, а не по ширине.

Требования

  • Python 3.8+
  • Pillow (pip install pillow)

Файлы проекта

hand-writter/
├── handwrite.py          # основной скрипт
├── requirements.txt      # Pillow
├── run.sh                # команды-обёртки
├── README.md             # этот файл
├── AGENTS.md             # руководство для агентов/разработчиков
└── examples/             # примеры вывода

Подробности о внутреннем устройстве и правилах изменения кода — в AGENTS.md.