Skip to content

✨ Add SVG, HTML, and PPTX renderers#16

Open
sjquant wants to merge 2 commits into
mainfrom
claude/html-svg-ppt-renderer-f3zqmr
Open

✨ Add SVG, HTML, and PPTX renderers#16
sjquant wants to merge 2 commits into
mainfrom
claude/html-svg-ppt-renderer-f3zqmr

Conversation

@sjquant

@sjquant sjquant commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Why

quickthumb only rendered raster output (PNG/JPEG/WEBP). The same layer spec is just as useful as a vector graphic, a shareable web page, or an editable slide — without rebuilding the design in another tool.

Changes

canvas.render() now detects .svg, .html, and .pptx extensions, with matching in-memory methods:

canvas.render("card.svg")            # also .html / .pptx
svg = canvas.to_svg(embed_fonts=True)
html = canvas.to_html(title="Launch card")
pptx_bytes = canvas.to_pptx()        # requires quickthumb[pptx]

Hybrid export strategy — layers the target format can express are emitted as native, editable primitives positioned with the same layout math as the raster renderer; everything else is embedded as pixel-exact PNG fragments rendered by the existing PIL pipeline:

Layer SVG / HTML PPTX
Background color / gradients native rect + gradient defs native fill (linear native, radial as picture)
Outline / shapes native elements incl. rotation, stroke/shadow/glow autoshapes (stars, pills, freeform polygons)
Text: wrapping, rich parts, letter spacing, gradient fills, effects, rotation, auto-scale native <text> per line/run editable text boxes with per-run styling
Groups (auto-layout) children exported natively at layout positions same
Images, image glyph fills, SVG-with-effects embedded PNG fragment embedded picture
Blend modes / custom layers layers below the last one are flattened into one PNG so blending sees its backdrop same
  • SVG output reproduces the PNG render almost pixel-for-pixel (validated in tests by rasterizing with cairosvg; mean channel difference < 5/255 on a vector-only spec).
  • embed_fonts inlines used fonts as @font-face data URLs; HTML defaults to embedded fonts so files are self-contained.
  • New optional extra quickthumb[pptx] (python-pptx); SVG/HTML need no new dependencies. The CLI picks formats from -o card.svg etc. automatically.
  • 48 new black-box tests; docs: new "Exporting to SVG, HTML & PPTX" page, installation/API/README updates.

PowerPoint lays text out with its own font metrics, so PPTX text placement is a close approximation rather than pixel-identical (documented).

https://claude.ai/code/session_01XRy5d1z14AgR3caayjjATH


Generated by Claude Code

claude added 2 commits June 12, 2026 11:48
Render canvases to vector and document formats alongside PNG/JPEG/WEBP:

- canvas.render() detects .svg/.html/.pptx extensions; new to_svg(),
  to_html(), and to_pptx() methods
- Backgrounds, gradients, outlines, shapes, and text (wrapping, rich
  parts, letter spacing, effects, rotation) export as native, editable
  primitives using the same layout math as the raster pipeline
- Raster images, image glyph fills, blend modes, and custom layers are
  embedded as pixel-exact PNG fragments; layers below the last
  blend/custom layer are flattened so blending sees its backdrop
- Optional embed_fonts inlines used fonts as @font-face data URLs
- PPTX export maps text to editable text boxes and shapes to autoshapes
  via the new optional quickthumb[pptx] extra (python-pptx)

https://claude.ai/code/session_01XRy5d1z14AgR3caayjjATH
Each snapshot stacks the PIL raster render (top) against the export
rasterized back to pixels (bottom) with a magenta divider, so export
fidelity can be judged visually like the existing rendering snapshots.

- Five SVG comparison scenes: shapes/gradients/outline, text styles and
  effects, rich text and gradient fills, auto-layout groups, and
  blend-mode flattening with embedded images
- PPTX comparisons rasterize through LibreOffice and skip when it is
  unavailable; regenerate with --inline-snapshot=create
- conftest pins fontconfig to the repo fonts so cairosvg resolves the
  same font files as the PIL pipeline on any machine

https://claude.ai/code/session_01XRy5d1z14AgR3caayjjATH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants