# handwrite.py Python-скрипт, превращающий текст в картинку рукописного текста с **поддержкой кириллицы** (полный русский алфавит, включая `Ё`, `щ`, `ъ`, `э`, `ю`, `я`). Чернила — **синие**, с имитацией письма ручкой. ## Возможности - 🖋️ **Синие чернила «как рукой»**: имитация письма ручкой — дрейф «давления» (коррелированные тёмные/светлые участки), полупрозрачные чернила, неровный край мазка - ✅ Полная поддержка кириллицы (автоподбор рукописного шрифта с проверкой наличия всех глифов; приоритет — `Marker Felt`) - 📐 Корректное выравнивание: обычные буквы (`а`, `о`, `н`, `б`, `й`) на одной базовой линии, буквы с нижними выносными (`р`, `у`, `д`, `ц`, `щ`) — с хвостами ниже, точки/запятые — внизу строки, спецсимволы (`$ ~ % @ # & …`) — по дизайну шрифта - 📝 Перенос по словам + сохранение `\n` из входного файла/STDIN - 📓 «Тетрадная» линейная бумага (`--lined`) - 🎨 Настройка цвета чернил/бумаги/линий, размера шрифта, полей - 📥 Ввод: аргументом, из файла (`-i`, с переносами строк), через STDIN - 🔒 Воспроизводимый результат через `--seed` ## Установка ```bash pip install -r requirements.txt # нужна только Pillow ``` или через обёртку (создаст venv): ```bash ./run.sh init ``` ## Быстрый старт ```bash # текст аргументом 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` | случайный | Зерно ГПСЧ для воспроизводимости. | ## Примеры использования ```bash # крупный текст на тёплой бумаге 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` передаются после `--` (или просто в конце): ```bash ./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`.