# pdf2epub Конвертация PDF, собранного из электронной книги (Producer: calibre), в EPUB/AZW3 для Kindle **с сохранением форматирования**: курсив, полужирный, заголовки глав, врезки, иллюстрации, склейка абзацев через границы страниц. ## Зачем не `ebook-convert` напрямую Прямая конвертация `ebook-convert book.pdf book.epub` теряет курсив: poppler определяет начертание по имени шрифта и не опознаёт сокращённые имена вроде `MinionPro-It` (без подстроки `Italic`). На «The Unicorn Project» получилось **435 курсивных фрагментов в PDF против 1 тега `` в EPUB**. Плюс calibre размечает основной текст как `

` (2817 штук), потому что определяет заголовки по кеглю относительно самого частого. `scripts/pdf2html.py` извлекает текст через PyMuPDF, где начертание берётся из свойств span'а, и сам раскладывает блоки по семантике. ## Что делает скрипт - курсив/полужирный — по имени шрифта span'а (`-It`, `Italic`, `Bold`, `Semibold`); - заголовки — по кеглю: `>= 28` или декоративный шрифт — `h1.title`, `>= 24` — `h1` (главы и части), `>= 17` — `h2` (подзаголовок с датой); - врезки (дневник, чаты, слайды) — отдельный шрифт семейства → `p.note`; - абзац = блок PDF; блок без красной строки в начале страницы приклеивается к абзацу с предыдущей страницы; - переносы на конце строки снимаются, соседние `` схлопываются; - иллюстрации выгружаются в `images/`, обложка рендерится со страницы 1 в 150 dpi; - позиционирование не сохраняется намеренно — текст должен течь под любой размер шрифта на читалке. ## Подключение как скил Claude Code Репозиторий одновременно является скилом (`SKILL.md` в корне) и клонируется **прямо в каталог скила** — никаких симлинков и зависимости от `~/Projects`, структура каталогов на разных ПК может не совпадать: ```bash git clone https://git.katze-lab.ru/chesirecatt/pdf2epub.git ~/.claude/skills/pdf-to-kindle ``` Скил `pdf-to-kindle` появится в списке доступных при следующем запуске сессии. Ручной клон нужен только если нет синхронизации памяти. **Штатный путь — автоматический:** репозиторий перечислен в массиве `SKILL_REPOS` в `sync.sh` репозитория [`claude-memory`](https://git.katze-lab.ru/chesirecatt/claude-memory), который крутится по таймеру `claude-memory-sync.timer` раз в 10 минут. На новом ПК скил клонируется сам при первом же прогоне синхронизации памяти, дальше обновляется. Ручных шагов и правки systemd-юнита не требуется. Синхронизация односторонняя (`pull`): правки вносятся и пушатся руками из `~/.claude/skills/pdf-to-kindle`. Чтобы добавить в автосинхронизацию ещё один скил — строка в `SKILL_REPOS` формата `" <имя каталога скила>"`. ## Требования PyMuPDF и calibre: ```bash python3 -m venv ~/.venvs/pdf2epub ~/.venvs/pdf2epub/bin/pip install pymupdf sudo dnf install calibre # если ebook-convert ещё нет ``` ## Использование Разведка — какие в PDF шрифты и кегли (пороги в скрипте подобраны под вёрстку 15pt/letter, для другой книги их правят по этому выводу): ```bash ~/.venvs/pdf2epub/bin/python scripts/pdf2html.py --fonts book.pdf ``` Конвертация: ```bash ~/.venvs/pdf2epub/bin/python scripts/pdf2html.py book.pdf out/book.html ebook-convert out/book.html "Название.epub" \ --title="Название" \ --authors="Автор" \ --language=en \ --cover=out/images/cover.jpg \ --level1-toc='//h:h1' --level2-toc='//h:h2' \ --page-breaks-before='//h:h1' \ --no-default-epub-cover ebook-convert "Название.epub" "Название.azw3" ``` `--level1-toc`/`--level2-toc` обязательны: без них calibre строит оглавление своей эвристикой и ломает разбивку по главам. ## Куда класть на Kindle - `.epub` — через Send to Kindle (веб или почта), Amazon конвертирует на своей стороне; - `.azw3` — по USB прямо в `documents/` на устройстве. ## Перевод (опционально) Перевод делает сторонний проект [`vetermanve/book_translator`](https://github.com/vetermanve/book_translator) (DeepSeek или локальная Ollama). **Репозиторий не модифицируется** — он вызывается через свой штатный CLI и форматы файлов. `scripts/translate.py` — мост: раскладывает наш XHTML в его входной JSON, запускает `03_translate_parallel.py --all`, собирает результат обратно. Подготовка (один раз): ```bash git clone https://github.com/vetermanve/book_translator.git ~/Projects/book_translator ~/.venvs/pdf2epub/bin/pip install openai python-dotenv # openai нет в их requirements.txt export DEEPSEEK_API_KEY=... # либо .env в рабочем каталоге, либо USE_OLLAMA ``` Сначала проверка, нужен ли перевод вообще (язык, объём; ничего не тратит): ```bash ~/.venvs/pdf2epub/bin/python scripts/translate.py out/book.html out/book.ru.html \ --repo ~/Projects/book_translator --workdir out/tr --check-only ``` Если книга уже на целевом языке, скрипт откажется переводить (`--force` переопределяет). Сам перевод: ```bash ~/.venvs/pdf2epub/bin/python scripts/translate.py out/book.html out/book.ru.html \ --repo ~/Projects/book_translator --workdir out/tr --workers 12 ``` Прерванный перевод возобновляется: сторонний скрипт помнит готовые главы. Дальше `out/book.ru.html` упаковывается тем же `ebook-convert` с `--language=ru`. Курсив и полужирный переживают внешний переводчик в виде маркеров `⟦i⟧…⟦/i⟧`; на обратном пути баланс маркеров проверяется по каждому абзацу. Картинки, заголовки и порядок блоков вообще не покидают наш скрипт — наружу уходит только текст, сборка идёт по индексам. В отчёте после перевода: «без перевода» — главы, вернувшиеся с другим числом абзацев (оставлен оригинал), «разметка потеряна» — абзацы, где модель испортила маркеры и курсив снят. Оба числа должны быть близки к нулю. Самопроверка моста без сети и ключей: ```bash cd scripts && python3 test_translate.py ``` ## Проверка результата ```bash python3 - <<'EOF' import re t = open('out/book.html').read() print('курсив:', t.count(''), 'полужирный:', t.count('')) print('заголовки:', len(re.findall(r']+>', '', t).count(' ')) EOF ``` Двойных пробелов должно быть единицы, курсива — сотни. Ноль курсива означает, что имена шрифтов в PDF не попали под правило в `style()`. ## Ограничения - рассчитан на PDF с текстовым слоем; сканы требуют OCR и сюда не годятся; - пороги кеглей и семейство шрифта для врезок — константы под конкретную вёрстку, правятся руками по выводу `--fonts`; - колонтитулы и номера страниц не вырезаются: в PDF от calibre их нет. Для типографского PDF понадобится отбрасывать блоки по координате `y`. ## Проверено на `The Unicorn Project` (Gene Kim), 399 страниц: 40 заголовков, оглавление на 62 пункта, 430 курсивных фрагментов, 178 врезок, 5 иллюстраций, ~733 тыс. знаков.