Skip to main content

2pdf

Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. Also converts Markdown / Obsidian notes into beautiful CJK-safe styled PDF (and PNG/HTML/WeChat) with themes, Mermaid, and bookmarks. When Claude needs to fill a PDF form, process/generate/analyze PDFs at scale, or turn Markdown/Obsidian notes into PDF. Triggers: md to pdf, markdown to pdf, 转 PDF, Obsidian 导出 PDF, 笔记转 PDF, export note to PDF.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
Loveacup/jz-skills
آخر نشاط في المصدر
٧ يوليو ٢٠٢٦ في ١٦:١٩
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
51 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
2pdf
description
Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. Also converts Markdown / Obsidian notes into beautiful CJK-safe styled PDF (and PNG/HTML/WeChat) with themes, Mermaid, and bookmarks. When Claude needs to fill a PDF form, process/generate/analyze PDFs at scale, or turn Markdown/Obsidian notes into PDF. Triggers: md to pdf, markdown to pdf, 转 PDF, Obsidian 导出 PDF, 笔记转 PDF, export note to PDF.
# PDF Processing Skill > **Source repo**: https://github.com/Loveacup/jz-skills (path `shared/2pdf`) — to update this skill: `git pull` then re-run `python3 scripts/md2pdf_chrome.py --setup` (idempotent). ## Overview This skill covers PDF processing operations: extract text/tables, merge/split, create new PDFs, fill forms, and convert Markdown to styled PDF with CJK support. - **Markdown to PDF** (primary workflow): `scripts/md2pdf_chrome.py` — see below - **PDF operations** (merge, split, extract, create): see `references/pdf-operations.md` - **Fill PDF forms**: read `references/forms.md` and follow its instructions - **Advanced** (pypdfium2, pdf-lib, troubleshooting): see `references/advanced.md` - **Markdown to PDF internals** (pagination, font sizing, Mermaid, callouts): see `references/md2pdf-details.md` ## Quick Start ```python from pypdf import PdfReader, PdfWriter reader = PdfReader("document.pdf") print(f"Pages: {len(reader.pages)}") text = "" for page in reader.pages: text += page.extract_text() ``` ## Markdown to Beautiful PDF (CJK-safe) Convert Obsidian Flavored Markdown to styled PDF with perfect Chinese/Japanese/Korean rendering. **Script**: `scripts/md2pdf_chrome.py` **Prerequisites — one command**: `python3 scripts/md2pdf_chrome.py --setup` (first run may take minutes: creates the persistent venv `~/.venvs/pdf-skill`, installs `markdown`/`pypdf`/`css_inline`, installs Playwright Chromium if missing, vendors pinned mermaid/highlight.js locally, then runs a smoke render + verify — green means the whole chain works on THIS machine, mac or Windows). Node.js must be present (`brew install node` / `winget install OpenJS.NodeJS`); `pandoc` is optional (lifeboat only). > ✅ **Self-healing**: even without `--setup`, any render command run from a dependency-less `python3` auto-switches to (or auto-creates) the persistent venv and re-executes itself — no manual env work. Disable with `--no-bootstrap`. Setup is idempotent; re-run it after upgrades. ### Usage ```bash python scripts/md2pdf_chrome.py <md_file> [pdf_file] [header_text] \ [--format pdf|png|html|wechat] [--browser playwright|chrome|auto] \ [--theme NAME] [--page-size A4|430x932] \ [--verify] [--allow-diagram-errors] [--no-metadata] [--fallback pandoc] \ [--sm PATTERN] [--xs PATTERN] [--sm-after PATTERN] [--xs-after PATTERN] # One-time environment bootstrap (idempotent; also: --preflight --fix) python3 scripts/md2pdf_chrome.py --setup # Preflight: check current interpreter + deps + browsers BEFORE rendering python scripts/md2pdf_chrome.py --preflight # human-readable python scripts/md2pdf_chrome.py --preflight --json # machine-readable (CI/quality gate) # Examples python scripts/md2pdf_chrome.py report.md python scripts/md2pdf_chrome.py report.md ~/output/report.pdf "My Report Title" python scripts/md2pdf_chrome.py note.md out.pdf --browser auto --verify # resilient render + quality gate python scripts/md2pdf_chrome.py report.md output.pdf --theme academic --sm "开发路线图" --xs-after "变更历史" ``` ### Output formats & resilience | Flag | Effect | |------|--------| | `--format pdf\|png\|html\|wechat` | Output format. `pdf` (default), `png` (full-page screenshot), `html` (standalone), `wechat` (CSS inlined for WeChat paste) | | `--browser playwright\|chrome\|auto` | Rendering engine. `playwright` (default, bundled Chromium); `chrome` (system Chrome via `executablePath`); `auto` tries bundled → system Chrome → (pdf only) pandoc, surviving runtime launch failures. Prints actual `engine` + `executable` to stderr | | `--page-size A4\|WxH` | `A4` (default) or a custom mobile size like `430x932`. Validated up front | | `--setup` | One-time idempotent bootstrap: persistent venv + deps + Playwright Chromium + pinned vendor assets (mermaid/hljs, `vendor.lock.json`) + smoke render acceptance. Alias: `--preflight --fix` | | `--preflight [--json]` | Health-check current interpreter, deps, browsers, pandoc, vendored assets, persistent venv — no rendering. Exit 0 ok / 1 fatal / 2 missing doc | | `--verify` | After rendering PDF, run delivery quality gate (`verify_pdf.py`): Mermaid-source leak, **Mermaid error-bomb text (fuzzy match)**, **diagram count reconciliation** (`/JZDiagramTotal` vs `/JZDiagramRendered` metadata), file size/magic, page count, metadata | | `--allow-diagram-errors` | Explicitly allow a PDF to be produced even when some Mermaid diagrams failed (default: **fail-fast, exit 3, no output file**) | | `--no-bootstrap` | Disable the automatic venv self-healing re-exec | | `--fallback pandoc` | Force the pandoc lifeboat (pandoc → HTML+CSS → system Chrome print-to-pdf). Style NOT faithful, no Mermaid, A4 only. Also auto-triggered by `--browser auto` when no Chromium can launch | | `--no-metadata` | Skip writing source frontmatter into PDF metadata (including diagram-count keys) | **Themes** auto-discover from `scripts/themes/*.css` (currently 18: academic, blue, dark, dracula, editorial, gruvbox-dark, gruvbox-light, kami, minimalist, newsletter, nord, sepia, social-card, solarized-dark, solarized-light, swiss, warm-academic, wechat-article). Use `--theme auto` to let the content-aware router pick a palette based on keywords, code density, and frontmatter. **Source frontmatter → PDF metadata**: `title` / `author` / `description` / `tags` / `aliases` / `created` / `modified` map to `/Title /Author /Subject /Keywords /CreationDate /ModDate`. `/Author` is written only when frontmatter explicitly declares `author` (privacy guard); `--no-metadata` disables the whole step. **Three-tier fallback** (rendering resilience — the 6-13 incident hardening): 1. **Primary** — Playwright bundled Chromium (`--browser playwright`, default). 2. **System Chrome** — `--browser chrome`, or `auto` when bundled Chromium fails to launch. 3. **Pandoc lifeboat** — `--fallback pandoc`, or `auto` when no Chromium launches (pdf only). Style not faithful; emergency use. **Quality-first fail-fast** (the 7-02 `==>` incident hardening — four defense layers): 1. **Fence-first preprocessing** — code fences & inline code are extracted to placeholders BEFORE `==highlight==`/wikilink/tasklist conversions, so Mermaid thick arrows (`A ==> B`) and code containing `[[ ]]`/`- [ ]` are never mangled. 2. **Render-time fail-fast** — every Mermaid block is `mermaid.parse()`-prechecked then rendered individually in the page; any failure aborts with exit 3, block number, error message and source head — **no PDF is produced**. Engine downgrade and the pandoc lifeboat are NOT triggered by diagram content errors. 3. **Parse precheck reporting** — errors are reported in seconds (before full page render), so the agent can fix the md immediately. 4. **Independent verify gate** — `--verify` re-checks the delivered PDF in a separate process: error-bomb fuzzy text scan + diagram count reconciliation via PDF metadata. **Cross-platform (mac + Windows)**: CJK font stacks include PingFang/YaHei (+ Consolas/Cascadia for code); system-Chrome discovery covers `/Applications`, `%ProgramFiles%`, Linux paths; Playwright cache detection covers `Library/Caches`, `.cache`, `%LOCALAPPDATA%`; no `/tmp` hardcoding (uses the platform temp dir); vendored assets live next to `scripts/`. Deploy/sync shell scripts remain mac-side; on Windows just `git pull` + `--setup`. ### Claude Code Relay Workflow The script and Claude Code work as a team. The script handles rendering mechanics, Claude Code handles content intelligence. ``` Step 1: Script runs → outputs Outline + PDF (with defaults) Step 2: Claude Code reads Outline + document head (first ~5 lines) and tail (last ~20 lines) → decides layout Step 3 (if needed): Claude Code re-runs with flags → script wraps matching content and renders ``` **CLI directives** (script automatically wraps matching content, no file editing needed): | Flag | Effect | |------|--------| | `--theme NAME` | Set visual theme: `blue` (default), `dark`, `academic`, `auto` — auto-discovered from `scripts/themes/*.css`. `auto` uses the content-aware router. | | `--sm "heading text"` | Wrap children of matching heading in `text-sm` (12px) | | `--xs "heading text"` | Wrap children of matching heading in `text-xs` (11px) | | `--sm-after "text"` | Wrap from matching line to end of document in `text-sm` (12px) | | `--xs-after "text"` | Wrap from matching line to end of document in `text-xs` (11px) | `--sm`/`--xs`: case-insensitive substring match against **heading text**, wraps child sections. `--sm-after`/`--xs-after`: case-insensitive substring match against **any line**, wraps from that line to EOF. Use for non-heading content like metadata/changelog at document end. **Manual markers** can also be inserted into Markdown (raw HTML, preserved by `md_in_html` extension): | Marker | Effect | |--------|--------| | `<div style="page-break-before:always"></div>` | Force page break | | `<div class="text-sm" markdown="1">...</div>` | Shrink to 12px | | `<div class="text-xs" markdown="1">...</div>` | Shrink to 11px | **Decision heuristics** for Claude Code (not hardcoded in script): - **Outline**: 5+ child headings with avg <500c → `--sm` to shrink the section - **Head/Tail**: metadata (版本/日期/作者) or changelog (变更历史) → `--xs-after` - Section <300c → don't break before it, let it flow with neighbors - Section >2000c → consider breaking before it - Short Phase (e.g. Phase 1: 226c) → no break before it Most documents need zero intervention (one run). Only complex documents with mixed section sizes or metadata/changelog need a second pass with flags. ### Pipeline ``` Obsidian MD → preprocess → Python markdown (md_in_html) → section wrap → styled HTML + JS → Playwright Chromium → PDF ``` 1. **Preprocess**: Strip YAML frontmatter, convert all 26 Obsidian callout types (including foldable), remove wikilinks, convert highlights (`==text==` → `<mark>`), convert task lists, embed local images as base64 2. **Convert**: Python `markdown` library with extensions: `tables`, `fenced_code`, `toc`, `sane_lists`, `md_in_html`, `footnotes` 3. **Section Wrap**: Post-process HTML — wrap `<h2>` into `<section class="doc-section">`, wrap `<h3>` into `<div class="doc-subsection">` 4. **Mermaid**: Convert mermaid code blocks → `<div class="mermaid">`, load pinned Mermaid JS vendored next to the script (`scripts/mermaid.min.js` + `vendor.lock.json`, downloaded by `--setup`), auto-scale SVG 5. **Syntax Highlighting**: highlight.js CDN with theme-aware styling (atom-one-dark / atom-one-light) 6. **Content Adaptation JS**: Adaptive table font sizing (5+ cols → 10px, 7+ → 9px), section density analysis (auto-shrink dense sections) 7. **Render**: Playwright Chromium headless — `waitForFunction` waits for Mermaid SVG rendering, `networkidle` ensures all resources loaded, then `page.pdf()` with A4 format + page numbers + native bookmarks & accessibility tags (`outline: true, tagged: true`) 8. **Post-process**: Remove blank pages + write metadata via pypdf `clone_from` (preserves native outline/tags); pypdf bookmark builder kept only as fallback for PDFs without a native outline (e.g. pandoc lifeboat) For pagination rules, font sizing tables, Mermaid details, callout types, and CSS customization, see `references/md2pdf-details.md`. ### Pitfalls **Mermaid failures never reach the PDF (by design).** If a render exits with code 3 and a `图#N` error listing, the md has a genuine Mermaid syntax error — fix the listed block and re-run. Historical note: thick arrows `==>` used to be destroyed by the highlight preprocessor (2026-07-02 incident); fence-first protection fixed this permanently, so `==>` is safe to use now. **Playwright PDFs are heavy.** A 7-page CJK document can produce a ~1.9MB PDF because Chromium embeds all fonts and full CSS. This routinely times out when delivering via messaging platforms (Telegram MEDIA delivery, etc.). **Compression is ineffective.** Ghostscript (`-dPDFSETTINGS=/screen`) only shaves ~20% off font-heavy Playwright PDFs. `weasyprint` requires system libs (`libgobject-2.0-0`, pango) often missing. `fpdf2` chokes on `.ttc` system fonts. Splitting pages helps only marginally. **Delivery fallback strategy (proven):** 1. Generate the styled PDF with `md2pdf_chrome.py` — save to local disk 2. Send the **markdown source** as a text message to the user (it's ~12KB) 3. Tell the user the PDF path on local disk for direct opening 4. If local delivery is not an option, consider `md2pdf_browser.py` which uses the same Playwright pipeline but may handle differently **Prefer this pattern when the user asks "make a PDF and send it":** - Generate PDF → note size → if >500KB, preemptively send markdown + local path - Don't waste turns on compression — it won't reduce enough for Playwright PDFs ## Quick Reference | Task | Tool | Details | |------|------|---------| | **Markdown to PDF** | `scripts/md2pdf_chrome.py` | Playwright Chromium, CJK-safe | | Merge/Split/Rotate PDFs | pypdf | `references/pdf-operations.md` | | Extract text | pdfplumber | `references/pdf-operations.md` | | Extract tables | pdfplumber | `references/pdf-operations.md` | | Create PDFs | reportlab | `references/pdf-operations.md` | | CLI merge/split | qpdf / pdftk | `references/pdf-operations.md` | | OCR scanned PDFs | pytesseract | `references/pdf-operations.md` | | Fill PDF forms | pypdf / pdf-lib | `references/forms.md` | | pypdfium2, pdf-lib | advanced libs | `references/advanced.md` | | Page headers/footers | `scripts/md2pdf_chrome.py` | Playwright, auto page numbering |
عرض على GitHub