feat(pptx): import table styles, live charts, and EMF/WMF fallbacks#42
Merged
Conversation
…backs Implements the round-2 plan from #38. Three deferred items from #36 land together so real-world decks (e.g. Dickinson sample) stop dropping recognisable content. - Table styles: parse ppt/tableStyles.xml, resolve <a:tableStyleId>, apply header/banded/firstCol/lastRow fills with cell-level overrides winning. TableElement gains rowAltFill / firstColFill / lastColFill / lastRowFill / hasHeader / bandRows / per-region text-colour fields. - Charts: emit ImageElement when the chart part ships a cached preview, otherwise parse <c:barChart>/<c:lineChart>/<c:pieChart>/etc. into a new ChartElement and render live via a lazy-loaded ECharts import. Source <p:graphicFrame> OOXML preserved on the element for round-trip. - EMF / WMF: prefer raster siblings (alt blip / extra rels / same-basename PNG); fall back to decoding the metafile in-browser via emf-converter. Headless environments without Canvas keep the legacy diagnostic-skip. - Bonus fix: tint / shade modifiers now operate per-RGB-channel per ECMA-376 §20.1.2.3 instead of as an HSL-luminance shift, so pastel Office accents (Medium Style 2 banded rows, etc.) stop coming out oversaturated. Adds emf-converter + echarts as runtime deps. Tests: 35 passing, including new round-2 fixtures for each item.
…round-2-impl # Conflicts: # packages/slidewise/src/lib/pptx/deckToPptx.ts # packages/slidewise/src/lib/pptx/pptxToDeck.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the round-2 plan from #38. Three deferred items from #36 land together so real-world client decks stop dropping recognisable content on import.
Closes the implementation half of #38.
1. Table styles
ppt/tableStyles.xmlonce per deck (resolved viapresentation.xml.rels), honour file-level<a:tblStyleLst def=\"…\">default.<a:tblPr><a:tableStyleId>and apply the matching style's parts (wholeTbl/firstRow/lastRow/firstCol/lastCol/band1H/band2H).<a:tblPr>flags (firstRow,firstCol,lastRow,lastCol,bandRow) decide which parts apply; cell-level<a:tcPr><a:solidFill>still wins as an override.TableElementgainsrowAltFill,firstColFill,lastColFill,lastRowFill,hasHeader,bandRows, and per-region text-colour overrides; the renderer applies them in PPTX-faithful precedence.2. Charts — cached image + live rendering
<p:graphicFrame>with<c:chart>first tries the chart part's cached raster preview (ppt/charts/_rels/chartN.xml.rels→…/image) and emits anImageElement.ChartElement(bar/column/line/area/pie/doughnut, withstandard/stacked/percentStackedgrouping, series fills, value labels, number-format codes, optional title) and rendered live via a lazy-loaded Apache ECharts import.<c:spPr><a:solidFill>wins; otherwise PowerPoint's default-palette cycletheme.accent{(c:idx % 6) + 1}is used.<p:graphicFrame>OOXML is preserved on the element so save round-trips re-emit the source chart part verbatim (including its embeddedxlsxworkbook).setOption(option, true)+ explicit per-seriesitemStyle.colorso palette merging can't drop colours when multiple series share a name.3. EMF / WMF — raster fallback + Canvas decode
<p:pic>references EMF/WMF, the importer first looks for a renderable sibling: alt blip in<a:extLst>, extra rels entry on the picture, or same-basename PNG/JPEG/SVG in the slide rels.emf-converter(Canvas-based EMF/WMF replayer) and rendered as PNG. The Dickinson sample wordmark (EMF-only) now appears instead of dropping.Canvas/OffscreenCanvas(SSR, Node) gracefully fall back to the legacy diagnostic-skip — never throws.Bonus: tint / shade fix
<a:tint val=\"20000\"/>and<a:shade>modifiers now operate per-RGB-channel per ECMA-376 §20.1.2.3 (mix with white / black respectively) instead of as an HSL-luminance shift. This was silently over-saturating the pastel Office accent palette — most visible on table-style band rows like "Medium Style 2 – Accent 1" whereaccent1 @ tint 20%should be#F2CCCC(light pink), not the saturated red the old code produced.What's still out of scope
TTCOMPRESSEDfonts, animations, SmartArt — explicit non-goals.Dependencies
emf-converter^1.1.6 (MIT, 0 deps, ~310 KB unpacked) — Canvas-based EMF/WMF decoder.echarts^6.0.0 — lazy-loaded only when a deck actually contains aChartElement.Test plan
pnpm tsc --noEmit -p tsconfig.lib.jsonclean.pnpm vitest run— 35/35 passing (4 new fixtures inround2.test.tscover table styles, cached chart, EMF raster sibling, EMF-only skip).Dickinson_Sample_Slides.pptx, eyeballed:Dickinsonwordmark (EMF) renders via in-browser decode.Bundle impact
emf-converter: ~310 KB shipped only when a deck triggers the EMF fallback (dynamicimport()).echarts: lazy-loaded on firstChartElementrender — zero impact for chart-free decks.