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/.
8.8 KiB
AGENTS.md — hand-writter
Руководство для агентов (и людей), работающих с репозиторием hand-writter.
О проекте
handwrite.py — CLI-утилита на Python, превращающая текст в картинку рукописного
текста с поддержкой кириллицы (полный русский алфавит, включая Ё, щ, ъ,
э, ю, я). Единственная зависимость — Pillow (PIL).
Ключевые особенности:
- Автоподбор рукописного шрифта из системы с проверкой покрытия кириллицы
(без сторонних библиотек — только Pillow: рендер символа и сравнение с
notdef-глифом). Приоритет:Marker Felt, затемSnell Roundhand, затем любой шрифт с кириллицей. - Синие чернила по умолчанию (
#1a3b8c) с имитацией письма ручкой: коррелированный дрейф «давления» (тёмные/светлые участки), полупрозрачные чернила, неровный край мазка. - Выравнивание глифов — стандартное PIL
text((x, line_top))(через маску в_stamp_glyph). Все обычные буквы (а, о, н, б, й) стоят на одной baseline, буквы с нижними выносными (р, у, д, ц, щ) опускают хвосты ниже — строчная «р» ниже обычных букв, точки/запятые внизу, спецсимволы ($ ~ % @ …) — по дизайну шрифта. Не вводите ручное смещение «по ink_bottom» — оно ломает б/й/н и обрезает глифы. - Перенос по словам + сохранение
\nиз входного файла/STDIN. - Тетрадная «линейная» бумага (
--lined), цвета чернил/бумаги/линий, синие палитры и градиенты оттенков.
Структура
hand-writter/
├── handwrite.py # основной скрипт (точка входа)
├── requirements.txt # Pillow>=9.0.0
├── run.sh # обёртка-команды: init/upd/render/...
├── README.md # пользовательская документация
├── AGENTS.md # этот файл
└── examples/ # примеры вывода
├── blue_pen.png
├── blue_pen_lined.png
├── multiline.png
└── sample_input.txt
Окружение и запуск
- Python 3.8+ (в
run.shпредполагаетсяpython3.13; если его нет — отредактируйтеPYвrun.shили используйте системныйpython3). - Активация venv:
source .venv/bin/activate(через./run.sh init). - Прямой запуск:
python3 handwrite.py "Текст" -o out.png. - Команды-обёртки:
./run.sh render "Текст"и др. (см. ниже).
Правила работы с кодом
-
Не добавляйте новых зависимостей без крайней необходимости. Скрипт намеренно зависит только от Pillow — это упрощает установку в изолированных средах. Любая новая зависимость должна быть обоснована и добавлена в
requirements.txt. -
Сохраняйте поддержку кириллицы. Любое изменение рендера/шрифтов должно проверяться на полном русском алфавите (см.
CYRILLIC_TESTвhandwrite.py). Не полагайтесь на «визуальную» проверку — шрифт может отрисовыватьnotdefдля отсутствующих глифов; используйте_font_covers_cyrillic(). -
Выравнивание — стандартное PIL. В
_stamp_glyphглиф рисуется маской с origin в канвасе и композируется так, чтобы совпадать сtext((x, line_top)). НЕ прижимайте ink_bottom вручную к baseline и НЕ сдвигайте глифы по bbox — это ломает б/й (обрезает) и делает их «слишком низкими». Канвас берётся по абсолютным границам bbox (включая отрицательные bbox[0]/bbox[1] для Ё, р). Знаки препинания рисуются с jitter=0 (чёткие точки), но тем же выравниванием. -
Сохраняйте переносы строк.
wrap_textиспользуетsplitlines()— каждая строка входа становится отдельной строкой на картинке. Не «схлоптывайте» пустые строки без явного флага. -
Не ломайте CLI-совместимость. Новые параметры добавляйте с значениями по умолчанию, не меняйте семантику существующих.
-
Внесение изменений: после правок проверяйте
python3 -c "import ast; ast.parse(open('handwrite.py').read())"— синтаксис;- запуск на кириллице с точками/запятыми и многострочным файлом;
- что точки-знаки остаются в нижней зоне строки.
Команды (run.sh)
| Команда | Описание |
|---|---|
./run.sh init |
Создать venv и установить зависимости |
./run.sh upd |
Обновить зависимости |
./run.sh render "текст" |
Рендер текста-аргумента → out/handwriting.png |
./run.sh lined "текст" |
Рендер на тетрадной бумаге |
./run.sh big "текст" |
Крупный шрифт (64pt) на тёплой бумаге |
./run.sh calm "текст" |
«Спокойный» почерк (jitter 0.3, seed 42) |
./run.sh plain "текст" |
Ровный текст (без дрожания/поворота строк) |
./run.sh render-file file.txt |
Рендер файла (с переносами строк) |
./run.sh poetry file.txt |
Многострочный файл → тетрадь, крупный шрифт → out/poetry.png |
./run.sh render-stdin |
Чтение из STDIN (echo "..." | ./run.sh render-stdin) |
./run.sh list-fonts |
Показать доступные рукописные шрифты с кириллицей |
./run.sh examples |
Перегенерировать примеры в examples/ |
Все команды рендера (render, lined, big, calm, plain, poetry,
render-file, render-stdin) принимают доп. опции handwrite.py после --,
например: ./run.sh render "Текст" -- --jitter 0.4 --seed 7 --lined.
Тестовые сценарии (обязательно прогонять при правках)
# кириллица с б/й/р, точками и спецсимволами (б/й на baseline, р ниже, точки внизу)
python3 handwrite.py "байты йогурт река. \$ ~ % @ # конец!" -o /tmp/t1.png
# многострочный файл (каждая строка файла → строка на картинке)
printf 'Строка 1.\nСтрока 2.\nСтрока 3.\n' > /tmp/m.txt
python3 handwrite.py -i /tmp/m.txt -o /tmp/t2.png --lined
# синий (по умолчанию) + тетрадь
python3 handwrite.py "Текст" --lined -o /tmp/t3.png
Чего не делать
- Не коммитьте
.DS_Store,.venv/, временные*.pngвнеexamples/. - Не удаляйте
examples/— это демонстрация возможностей. - Не «упрощайте» проверку глифов кириллицы до
textbbox/ширины — это ненадёжно (узкие буквы, например «г», неотличимы отnotdefпо ширине). - Цвет чернил по умолчанию — синий. Палитры/градиенты намеренно убраны (раньше были, но усложняли). Не возвращайте мульти-цвет без явной просьбы.