Skip to content

Epic: chart rendering — PNG-via-CV pipeline (DOCX / PPTX / XLSX / HTML / PDF) #116

@DaveMoudy

Description

@DaveMoudy

What

Build a chart rendering pipeline that produces native-quality chart visuals in all five output formats (DOCX / PPTX / XLSX / HTML / PDF) from the same template tag, by routing every chart through the existing image-substitution path.

Revised architecture (post-spike findings, 2026-05-19)

Original plan was a 4-serializer matrix (OOXML c:chartSpace + SVG fragment + HTML+CSS bars + PNG external). Four rounds of empirical spike on portwood-staging proved:

  1. Blob.toPdf (Flying Saucer) silently drops inline SVG and SVG-via-CV-URL. Salesforce's hosted Flying Saucer instance lacks SVGSalamander / Batik on the classpath; per Microsoft's own docs the SVG ReplacedElementFactory is host-application plumbing not bundled with the engine.
  2. Word's "SVG support" is preservation-only. Saving an Insert > Picture > SVG in Word produces a dual-blip (PNG fallback + <asvg:svgBlip> extension). When the docx is opened, Word renders the PNG. Removing the PNG from the package and re-opening shows a placeholder — Word does NOT render the SVG for display. PowerPoint and Excel share the same OOXML image stack and behave identically.
  3. Word's local SVG rasterizer runs at Insert/Edit time only, not at file-open time. We can't access it from our pipeline.

Conclusion: PNG is the only image format every output renders. SVG buys nothing the existing path doesn't already provide.

The pipeline

chart tag at render time (record-page Generate, Bulk runner, etc.)
  ↓
Apex emits SVG  (deterministic — pure data → SVG string)
  ↓
LWC rasterizes via <canvas>.drawImage + toDataURL → PNG bytes
  ↓
PNG saved as ContentVersion linked to the source record (cached, see below)
  ↓
Existing image-substitution pipeline embeds the CV reference
  ↓
PNG renders natively in:
   DOCX (Word renders PNG)
   PPTX (PPT renders PNG)
   XLSX (Excel renders PNG)
   HTML (browser renders PNG)
   PDF (Flying Saucer renders PNG)

Every output gets the same PNG via the same {%ImageField}-style substitution that DocGen already does. No new image-embed plumbing per format.

Three free wins from PNG-as-CV-on-the-record

  1. Universal output support. One PNG per chart, five outputs. The chart tag is just "generate-and-attach-an-image-then-substitute-it."
  2. Cacheability. Re-rendering the same template against the same record reuses the existing chart CV. The resolver checks for a fresh CV before generating a new one.
  3. Author flexibility. If a template author wants more layout control than {#ChartBucket} gives them, they can reference the cached chart CV via {%FieldName} for arbitrary positioning/sizing/wrapping — same flexibility as any image field today.

v1 scope (sub-issue #117)

Browser-only LWC rasterization. Three flows are browser-driven and get charts:

  • docGenRunner (record-page Generate button) ✅
  • docGenBulkRunner
  • Future Experience Cloud LWCs if any return ✅

Three flows are server-side and do NOT get charts in v1:

  • DocGenFlowAction (Flow invocable) — render text-only placeholder where chart would go
  • DocGenBatch (Apex Batchable) — same
  • Signature pipeline — same

Documentation captures the limitation. Customers who file requests for server-side chart support trigger v2.

v2 scope (separate sub-issue, future)

External SVG→PNG rendering service (Heroku/Lambda) so Flow / batch / async paths can produce charts. The Apex side just becomes an HTTP callout returning PNG bytes; everything downstream is unchanged.

v3 scope (separate sub-issue, future)

OOXML native <c:chartSpace> serializer for customers wanting PowerPoint's "Edit Data" UI on top of the chart. Separate from this epic's "static visual fidelity" goal — that one's about editable native chart objects.

Sizing

~9 days total for v1:

  • Apex SVG emitter (2 days)
  • LWC rasterization helper (1 day)
  • Chart tag wiring + CV upload (1 day)
  • Caching layer (1 day)
  • e2e + apex tests + docs (4 days)

Customer story

"Author the report once. Render to PDF, Word, PowerPoint, Excel, or HTML — same Salesforce data, no manual chart updates. Browser-initiated generation rasterizes the chart to a high-quality PNG attached to the record; every output format embeds the same image. The chart is cached on the record, so re-renders are instant."

Out of scope

  • Server-side chart rendering (v2 — separate sub-issue)
  • Native editable OOXML charts with PowerPoint "Edit Data" UI (v3 — separate sub-issue)
  • 3D / sankey / mekko / treemap (could be added to the SVG emitter incrementally; not v1)

Spike artifacts

The spike scripts under scripts/spike-117-*.apex document the empirical findings. Re-run when Salesforce updates their hosted Flying Saucer with an SVG ReplacedElementFactory (which would change the matrix again).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bulk-generationRelated to batch/bulk document generationdocxRelated to DOCX output or client-side assemblyenhancementNew feature or requestpdfRelated to PDF output or Blob.toPdf()priority:P2Planned enhancement on the roadmap

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions