Skip to content

fix(pptx): render shape image fills, fix picture placeholders, and load embedded fonts#73

Merged
karthikmudunuri merged 3 commits into
mainfrom
karthikmudunuri/slide-render-comparison
Jun 2, 2026
Merged

fix(pptx): render shape image fills, fix picture placeholders, and load embedded fonts#73
karthikmudunuri merged 3 commits into
mainfrom
karthikmudunuri/slide-render-comparison

Conversation

@karthikmudunuri
Copy link
Copy Markdown
Member

Summary

Fixes a set of PPTX import-rendering fidelity gaps surfaced by a real-world deck (an "Education" template). Each was verified against the actual file; the font work was additionally verified in real headless Chrome (the browser's OTS sanitizer is far stricter than fontTools).

1. Picture / SVG fills on shapes

Shapes whose fill is an <a:blipFill> — the modern Office "icon" pattern, including dual PNG+SVG blips — now render their artwork. Previously these custGeom icons (globes, stars, grid textures, brand marks) imported with no fill and showed blank/grey.

  • Importer resolves the blip (prefers the sharper SVG embed) to a url("data:…") and feeds it into the existing fill field.
  • ShapeView paints the image clipped to the custGeom silhouette, or as a box-filling background for rect/rounded/circle.

2. Picture-placeholder handling

  • Empty picture placeholders inherited from the layout no longer leak onto the slide as grey "Insert Picture" prompt boxes.
  • Picture placeholders the slide hosts now inherit their rounded geometry + fill from the layout/master placeholder, so they render as the template intends.

3. Embedded fonts (EOT / MicroType-Express) now load

Embedded .fntdata fonts decode to browser-valid TTFs. Two independent bugs caused the browser's font sanitizer (OTS) to reject the whole font and fall back to a system typeface:

  • Composite glyphs carrying WE_HAVE_INSTRUCTIONS on a non-first component produced a malformed glyf table (a parser read a non-existent instructionLength past the glyph).
  • Format-12 cmap subtables shipped a non-zero language field (1007); OTS requires 0 on non-Macintosh platforms.

4. Weight-named font families

Weight-named embedded families (e.g. Montserrat Bold, Montserrat Semi-Bold) are now aliased to their base family at the matching numeric weight, so bold/semibold text bound to the base family uses the real embedded face instead of a synthetic bold. Display-only — deck.fonts (PPTX export) is untouched.

Verification

  • All 8 embedded fonts load in headless Chrome with zero OTS errors (font1…font8 = true); base-family weights (Montserrat 400/600/700) resolve to the real faces.
  • New tests: image-fill rendering (3), CTF composite reconstruction, cmap language sanitization, splitFamilyWeight (3 cases).
  • Full slidewise suite: 70 passed, 9 pre-existing skips. Monorepo typecheck: clean.

Notes

  • Export/round-trip is unaffected: shape source XML is preserved, and the weight aliasing is display-only.
  • Line-height (1.2) was investigated and intentionally left unchanged — the observed title-overlap was caused by fallback-font width, not line spacing.

… handling

- Resolve <a:blipFill> on shapes to an image fill (prefers the SVG blip) so
  custGeom icons, globes, stars and grid textures render instead of blank.
- ShapeView paints the image clipped to the custGeom path, or as a
  box-filling background for rect/rounded/circle shapes.
- Suppress empty layout picture-placeholder prompt boxes from leaking onto
  the slide; on-slide picture placeholders inherit geometry + fill from the
  layout/master placeholder.
- Clear WE_HAVE_INSTRUCTIONS on every composite component (not just the
  first) so the reconstructed glyf table parses; a stray bit made OTS read a
  non-existent instructionLength past the glyph and reject the font.
- Sanitize cmap subtable 'language' to 0 on non-Macintosh platforms; some
  embedded faces ship format-12 language=1007, which OTS rejects.
- Alias weight-named embedded families (Montserrat Bold/Semi-Bold) to the
  base family at the matching numeric weight so base-family bold/semibold
  text uses the real face instead of a synthetic bold.
@karthikmudunuri karthikmudunuri merged commit 80e1b4e into main Jun 2, 2026
1 check passed
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.

1 participant