# Операции с PDF документами (v3)

Ты работаешь с PDF через готовые CLI-скрипты в песочнице. НЕ пиши код вручную — вызывай скрипты.

---

## S0. СТОП-ПРАВИЛА — читай ПЕРВЫМИ

⛔ ЗАПРЕЩЕНО писать Python-код для операций с PDF вручную.
Единственный разрешённый способ — вызов скриптов через `sandbox_bash`:
```bash
python $SKILLS_ROOT/pdf_operations_ru/scripts/merge.py file1.pdf file2.pdf -o $OUTPUT_ROOT/merged.pdf
```
⚠️ Если $SKILLS_ROOT недоступен: `sandbox_bash("ls $SKILLS_ROOT/pdf_operations_ru/scripts/")`.
Если пусто — скопируй нужный скрипт из навыка в $WORK_ROOT/ и запускай оттуда.

Зависимости (weasyprint, PyPDF2, pdfplumber, pymupdf) предустановлены в песочнице — запускай скрипты сразу, без pip install.

⛔ Весь ТЕКСТ в новые PDF рисует ОДИН движок — weasyprint (через `convert.py`). Кириллица, ₽, любые символы — корректно. Не ищи отдельный «генератор PDF».
⛔ НЕ используй `base64.b64decode(pdf_content)` — работай с файлами напрямую через пути.
Загруженные файлы доступны в `/tmp/`, результаты сохраняй в `$OUTPUT_ROOT/`.

---

## S1. WORKFLOW

| Задача | Шаги |
|--------|------|
| Узнать о PDF (метаданные, страницы, поля формы) | `pdf_info.py` |
| Создать документ / таблицу / текст | `glyphs.py` (если есть эмодзи/редкие знаки) → `convert.py` (HTML или Markdown) → `validate.py` |
| Создать презентацию (слайды) | `convert.py` со слайд-HTML → `validate.py` |
| Модификация существующего PDF | действие → `validate.py` |
| Извлечение данных | `extract_text.py` / `extract_tables.py` / `extract_images.py` |

**ОБЯЗАТЕЛЬНО** после создания или модификации PDF:
```bash
python $SKILLS_ROOT/pdf_operations_ru/scripts/validate.py $OUTPUT_ROOT/result.pdf
```
`validate.py` проверяет не только структуру, но и отрисовку шрифтов: если в PDF есть нерендерящиеся глифы (notdef/«квадраты», например кириллица в латинском шрифте) — статус будет **FAILED**, и он назовёт сами символы с кодпоинтами.

⛔ FAILED по глифам НЕ чинится пересборкой того же текста — шрифт от повторного рендера символ не приобретёт. Замени названные символы текстовым эквивалентом (`✅` → `[v]`, `₽` → `руб.`) и пересобери. Если замены нет и символ существенный — отдай файл с оговоркой в ответе, какие символы заменены; молча терять их нельзя. Проверить заранее: `glyphs.py` (см. S2).

---

## S2. СКРИПТЫ — справочник

Все скрипты: `$SKILLS_ROOT/pdf_operations_ru/scripts/`
Каждый скрипт поддерживает `--help` для полного списка параметров.

### Создание PDF: HTML / Markdown / DOCX → PDF (convert.py)
```bash
# HTML → PDF с CSS-пресетом
python scripts/convert.py --html doc.html -o $OUTPUT_ROOT/doc.pdf --css report
# Markdown → PDF (таблицы | ... | поддерживаются)
python scripts/convert.py --markdown doc.md -o $OUTPUT_ROOT/doc.pdf --css report
# DOCX → PDF
python scripts/convert.py --docx doc.docx -o $OUTPUT_ROOT/doc.pdf --css contract
# HTML-строка напрямую
python scripts/convert.py --html-string "<h1>Заголовок</h1><p>Текст</p>" -o $OUTPUT_ROOT/doc.pdf --css gost
```

CSS-пресеты:
| Пресет | Назначение |
|--------|------------|
| `gost` | ГОСТ-документ: A4, поля 2/1.5/2/3 см, Serif 14pt, абзацный отступ, выключка |
| `contract` | Договор: как ГОСТ, под юридические документы |
| `report` | Отчёт/КП: Sans 12pt, цветные заголовки, стилизованные таблицы (тёмная шапка, зебра) |
| `minimal` | Минимальный: Sans 12pt, без украшений |
| `presentation` | Слайды 16:9 landscape (297×167 мм), готовый класс `.slide` |
| `none` | Без пресета — рендерится ТОЛЬКО твой авторский CSS (`<style>`/`@page` в HTML) |

`--custom-css "<css>"` — передать произвольный CSS (заменяет пресет целиком).

**Таблицы и текст** делаются здесь же, отдельного скрипта нет:
- таблица → Markdown `| ... |` или HTML `<table>` + `--css report`;
- текстовый документ → Markdown/HTML + `--css gost` (или `report`).

### Презентации (слайды)
Дек — это HTML, где каждый слайд — блок с разрывом страницы. Два пути:

1. Быстрый дек на пресете — используй класс `.slide` из `--css presentation`:
```bash
python scripts/convert.py --html-string '<div class="slide"><h1>Заголовок дека</h1><p>Подзаголовок</p></div><div class="slide"><h2>Слайд 2</h2><ul><li>Пункт</li></ul></div>' -o $OUTPUT_ROOT/deck.pdf --css presentation
```

2. Полностью авторский дизайн — пиши свой `<style>` в HTML и рендери с `--css none`, чтобы пресет не вмешивался:
```html
<style>
  @page { size: 297mm 167mm; margin: 0; }
  * { margin: 0; box-sizing: border-box; }
  .slide { width: 297mm; height: 167mm; page-break-after: always; padding: 20mm 24mm; }
  .slide:last-child { page-break-after: auto; }
  h1 { font-size: 44pt; font-weight: 800; }
</style>
<div class="slide">...</div>
<div class="slide">...</div>
```
```bash
python scripts/convert.py --html deck.html -o $OUTPUT_ROOT/deck.pdf --css none
```
⚠️ Для слайдов НЕ оставляй документный пресет (`gost` по умолчанию) — он центрирует заголовки и добавляет абзацный отступ/выключку, ломая вёрстку. Бери `presentation` или `none`.

### Объединение
```bash
python scripts/merge.py file1.pdf file2.pdf file3.pdf -o $OUTPUT_ROOT/merged.pdf
python scripts/merge.py *.pdf --sort name -o $OUTPUT_ROOT/merged.pdf
```

### Операции со страницами
```bash
python scripts/pages.py extract input.pdf --pages 1,3,5-8 -o output.pdf
python scripts/pages.py split input.pdf --out-dir $OUTPUT_ROOT/
python scripts/pages.py delete input.pdf --pages 3,5,7 -o output.pdf
python scripts/pages.py rotate input.pdf --angle 90 --pages 1,3 -o output.pdf
python scripts/pages.py reorder input.pdf --order 3,1,2,5,4 -o output.pdf
python scripts/pages.py reverse input.pdf -o output.pdf
python scripts/pages.py insert-blank input.pdf --after 2 -o output.pdf
python scripts/pages.py insert input.pdf --insert other.pdf --after 3 -o output.pdf
```

### Информация о PDF
```bash
python scripts/pdf_info.py input.pdf
python scripts/pdf_info.py input.pdf --pages-detail
```

### Извлечение текста
```bash
python scripts/extract_text.py input.pdf
python scripts/extract_text.py input.pdf --pages 1,3,5-8
python scripts/extract_text.py input.pdf -o $OUTPUT_ROOT/text.txt
```

Битый PDF (`extract_text.py` падает с `Unexpected EOF` / `PdfminerException`) — сначала ремонт через `qpdf`, потом повтор извлечения:
```bash
qpdf "$INPUT_ROOT.pdf" $WORK_ROOT/fixed.pdf || qpdf --qdf --object-streams=disable "$INPUT_ROOT.pdf" $WORK_ROOT/fixed.pdf
python scripts/extract_text.py $WORK_ROOT/fixed.pdf
```
`pymupdf` устойчивее pdfplumber к обрыву потока — если ремонт не помог, извлекай через него.

### Извлечение таблиц
```bash
python scripts/extract_tables.py input.pdf --format print
python scripts/extract_tables.py input.pdf --format json -o tables.json
python scripts/extract_tables.py input.pdf --format csv -o table.csv
python scripts/extract_tables.py input.pdf --format excel -o tables.xlsx
python scripts/extract_tables.py input.pdf --page 1 --strategy text
```
Стратегии: `lines` (по умолчанию, для таблиц с линиями), `text` (для таблиц без рамок), `explicit`.

### Извлечение изображений
```bash
python scripts/extract_images.py input.pdf --out-dir $OUTPUT_ROOT/images/
```

### Защита паролем
```bash
python scripts/security.py encrypt input.pdf -o protected.pdf --user-password pass1 --owner-password pass2
python scripts/security.py decrypt input.pdf -o unlocked.pdf --password pass1
```

### Водяные знаки и штампы
```bash
python scripts/watermark.py text input.pdf -o output.pdf --text "КОНФИДЕНЦИАЛЬНО" --opacity 0.15 --angle 45
python scripts/watermark.py stamp input.pdf -o output.pdf --text "КОПИЯ" --position top-right --color red
```
Текст (в т.ч. кириллица) рисуется weasyprint и масштабируется под реальный размер страницы (работает и на landscape-деках). `--font-size 0` (по умолчанию для `text`) — авто-подгонка под ширину. Позиции штампа: `top-right`, `top-left`, `bottom-right`, `bottom-left`, `center`.

### Нумерация и колонтитулы
```bash
python scripts/overlay.py numbers input.pdf -o output.pdf --format "-- {n} --"
python scripts/overlay.py headers input.pdf -o output.pdf --header "ООО Компания" --footer "Конфиденциально" --number
```
Колонтитулы с кириллицей рендерятся корректно; формат номера поддерживает `{n}` и `{total}`.

### Формы PDF
```bash
python scripts/forms.py read input.pdf
python scripts/forms.py fill input.pdf -o filled.pdf --data '{"name": "Иванов", "date": "01.01.2025"}'
python scripts/forms.py fill-batch input.pdf --csv data.csv --out-dir $OUTPUT_ROOT/
python scripts/forms.py fill-checkboxes input.pdf -o filled.pdf --data '{"agree": true, "subscribe": false}'
```

### Проверка символов (ДО рендера, если в тексте есть эмодзи/редкие знаки)
```bash
python scripts/glyphs.py --text "Отчёт ✅ готов"
python scripts/glyphs.py --file $WORK_ROOT/report.html --json
```
Печатает символы, которые шрифт не нарисует, с кодпоинтом и причиной (`blank` или `notdef`).
Найденное заменяй текстовым эквивалентом ДО рендера: `✅` → `[v]`, `❌` → `[x]`, `→` → `->`.

### Валидация (ОБЯЗАТЕЛЬНО после создания/модификации)
```bash
python scripts/validate.py $OUTPUT_ROOT/result.pdf
```
Проверяет структуру + покрытие глифов (notdef/tofu → FAILED) и называет сами символы.

---

## S3. CUSTOM CODE — только если скрипты не покрывают задачу

Если задача выходит за рамки скриптов, пиши Python-код в `sandbox_bash`. Правила:
1. Используй предустановленные библиотеки: PyPDF2, weasyprint, pdfplumber, pymupdf
2. Текст в новые PDF рисуй через weasyprint (HTML→PDF), а не через шрифты ReportLab — иначе кириллица превратится в «квадраты»
3. Входные файлы в `/tmp/`, результаты в `$OUTPUT_ROOT/`
4. Завершай валидацией: `python scripts/validate.py <output_file>`

---

*Выполняй все операции через sandbox_bash. Используй --help для полного списка параметров любого скрипта.*
