openpencil/crates
Kayshen-X 6d0d8d31cd feat(shell): PDF multi-page export via skia built-in backend
Phase 4 — closes the last gap in the ExportDialog. Each PenPage
becomes one PDF page laid out at its content bounding box plus a
16-pt margin. Empty pages are skipped; all-empty docs return
'nothing to export' to match the raster export convention.

Mechanism: `skia_safe::pdf::new_document(&mut buf, None)` returns
the document; per-page `begin_page` / `end_page` reuses the same
`paint_node` pipeline as the raster path, so every variant the PNG
exporter handles (Rect / Ellipse / Polygon / Line / Path / Frame /
Group with rotation + corner radius) emits as real vector PDF ops —
glyphs and shapes stay selectable and zoom-clean. The TS app hand-
rolls a PDF stream (Catalog + Pages + Image XObjects with DCTDecode
JPEG blobs); skia's backend produces a smaller, sharper file.

Wiring:
  - `export.rs::page_bounds` + `paint_node` exposed as `pub(crate)`
    so the new `export_pdf.rs` sibling can reuse them.
  - `Cargo.toml`: skia-safe `pdf` feature flag enabled.
  - `persistence.rs::ExportImageConfirm` PDF branch now calls
    `export_pdf::export_pdf` instead of returning the placeholder
    error.
  - `ExportFormat::is_implemented` now returns true for every variant
    so the dialog stops greying out the PDF pill.

Tests: 2 unit tests in `export_pdf.rs` cover `%PDF-` header +
`%%EOF` trailer for a 2-page doc, plus the all-empty failure path.
197 total tests pass.

Phase 5 codex review still pending; will land in the next pass.
2026-05-14 14:06:18 +08:00
..
openpencil-app feat(openpencil-app): skeleton crate (Stage F entry placeholder) 2026-05-03 22:05:00 +08:00
openpencil-desktop feat(shell): PDF multi-page export via skia built-in backend 2026-05-14 14:06:18 +08:00
openpencil-shell-core feat(shell): PDF multi-page export via skia built-in backend 2026-05-14 14:06:18 +08:00
openpencil-shell-native feat(shell): export dialog + multi-format raster (PNG/JPEG/WEBP) + Property-panel preview 2026-05-14 14:02:52 +08:00
openpencil-shell-web feat(shell): export dialog + multi-format raster (PNG/JPEG/WEBP) + Property-panel preview 2026-05-14 14:02:52 +08:00
pen-codegen chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-core chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-engine chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-figma chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-types feat(pen-types): skeleton crate (bucket A) 2026-05-03 22:35:00 +08:00
wasm-libc-shim style(shell): cargo fmt --all (rustfmt-clean) 2026-05-10 18:47:33 +08:00
CLAUDE.md feat(shell): canonical .op loader + jian-core layout + visual fidelity pass 2026-05-14 09:26:08 +08:00