fix(pptx/render): emit valid SVG <image> for image-fill backgrounds#100
Conversation
renderDeckToSvg rendered a slide's image-fill background as a CSS
background shorthand inside fill="…" (center / cover no-repeat
url("data:image…")) — invalid SVG that strict rasterisers (resvg,
librsvg) reject, blocking a Chromium-free render path. The renderer now
recognises a url(...) anywhere in the value and emits a real <image>
element (slice for cover, meet for contain). Adds a strict-XML-parser
lock-in test over an image-background fixture.
…svg-js XMLValidator proves well-formedness only; resvg is the actual consumer. Add @resvg/resvg-js as a devDependency and drive an image-background slide through the package's default rasteriser (no injected hook), asserting a valid PNG of the expected dimensions (320x180). resvg threw on the old fill="...url(data:...)..." output, so this is a true guard.
|
Added a real-rasteriser guard on top of the
Confirmed resvg threw on the old |
…resvg/resvg-js" This reverts commit 3f9d393. Keep the resvg renderability check on the consumer side (the host serializer already ships @resvg/resvg-js) rather than dragging a platform-native binary into the package's CI. The bug was an SVG-validity (well-formedness) regression, which the pure-JS XMLValidator lock-in already catches — it was confirmed to reject the old malformed output. The package CI stays native-dep-free.
|
Reverted the resvg test + native devDependency (commit Rationale (agreed split):
This bug was an SVG validity regression (nested quotes / non-paint Net diff is back to three files (changeset + XMLValidator test + |
Problem
renderDeckToSvgrendered a slide's image-fill background as a CSSbackgroundshorthand dropped into an SVGfill="…"attribute:That is not valid SVG — it's a non-paint value, and the nested unescaped quotes terminate the attribute. Browsers parse it leniently, but every strict SVG rasteriser (
@resvg/resvg-js, librsvg, batik) rejects it:This was the single blocker to a Chromium-free render path (
parsePptx → renderDeckToSvg → resvg → PNG).Root cause
The pptx importer stores image backgrounds as a CSS
backgroundshorthand (pptxToDeck.ts:3592:center / cover no-repeat url("…")). The renderer's image-ref detection (isImageRef) only inspected the start of the value (startsWith("data:image"),/^url\(/), so the shorthand wasn't recognised as an image and fell through tosolidFrom, which returned the whole shorthand as a "named colour" →fill="…".renderBackgroundalready had a correct<image>branch; it just never reached it.Fix
isImageRefnow matches aurl(...)anywhere in the value (gradients have nourl(, so they're unaffected).imageHrefextracts the URL fromurl(...)wherever it appears (data URLs use a)-free base64 alphabet, so non-greedy-to-first-)is safe).imageFitPreserve:cover→xMidYMid slice,contain→xMidYMid meet, wired intorenderBackground.solidFrom(which delegates toisImageRef), though only backgrounds use this form today.Tests
Three new lock-in tests (9/9 green):
<image>with the data-URLxlink:href,preserveAspectRatio="xMidYMid slice", and nofill="…url(…".containbackground →preserveAspectRatio="xMidYMid meet".fast-xml-parser'sXMLValidator(the non-browser equivalent of the resvg check), with an image-background slide as the regression case. Verified the validator rejects the old malformed output, so the guard is meaningful.tsc --noEmitclean. Changeset:patch.