Skip to content

Math Equations (LaTeX / MathML → OMML)

The math: option on a text item emits a native, editable PowerPoint equation (OMML inside PowerPoint's <a14:m> markup-compatibility envelope). That option takes raw OMML. The @shbernal/ts-pptx/math subpath lets you author the equation in LaTeX or MathML instead and get the OMML to hand it.

LaTeX  --temml-->  MathML  --mathml2omml-->  OMML  -->  { math: … } on addText

Install the converters

The converters are optional peer dependencies: the core package does not pull them in, so consumers who never author math carry no extra weight. Install them to use this subpath:

sh
npm install temml mathml2omml

mathml2omml is LGPL. It is never bundled into this package's output (it stays a separate, replaceable dependency in your node_modules), and because it is opt-in, consumers with policies against LGPL can simply not install it.

Node-only. This subpath loads the converters synchronously via Node's createRequire, so it runs under Node, not in a browser bundle. It is an authoring helper; the OMML it produces is plain data you can persist and feed to math: from anywhere.

Usage

js
import TsPptx from '@shbernal/ts-pptx'
import { latexToOmml } from '@shbernal/ts-pptx/math'

const pptx = new TsPptx()
const slide = pptx.addSlide()

slide.addText([{ math: latexToOmml('x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}') }], {
	x: 1,
	y: 2,
	w: 8,
	h: 1,
})

await pptx.writeFile({ fileName: 'quadratic.pptx' })

The item's math value fully controls the paragraph; any text on the same item is ignored (see TextProps.math).

API

latexToOmml(latex, opts?)

Convert a LaTeX math expression to OMML.

  • latex: string: e.g. \sum_{i=1}^{n} i = \frac{n(n+1)}{2}.
  • opts.display?: boolean (default true) selects display (block) math: render in displayMode and wrap the result in a centered <m:oMathPara> display paragraph. With display: false, temml renders in inline mode and a bare <m:oMath> is returned.
  • Returns OMML: <m:oMathPara>…</m:oMathPara> (display) or <m:oMath>…</m:oMath> (inline). Both are accepted by the math: option; pass the display: false form together with inline: true on the text item to flow the equation mid-paragraph (see Inline math).
  • Throws on invalid LaTeX, surfacing temml's parse position, e.g. Invalid LaTeX (position 6): ….

mathmlToOmml(mathml)

Convert a MathML string (<math>…</math>) to OMML.

  • Returns a bare <m:oMath>…</m:oMath> with no namespace declarations (the math: envelope supplies the m prefix at emit time).

Output form

Both functions emit OMML in the m: (http://schemas.openxmlformats.org/officeDocument/2006/math) namespace with no namespace declarations of their own: the <a14:m> envelope that math: authors declares m. mathmlToOmml always returns a bare <m:oMath>; latexToOmml returns that same <m:oMath> wrapped in a centered <m:oMathPara> unless display: false. All three shapes (inner OMML, <m:oMath>, <m:oMathPara>) are valid inputs to math:.

Inline math

By default a math: item is emitted as its own centered display-math paragraph. To flow an equation in a sentence, between plain text runs, set inline: true on the text item and give it the bare <m:oMath> form (latexToOmml(tex, { display: false }) or mathmlToOmml(mathml)):

js
import { latexToOmml } from '@shbernal/ts-pptx/math'

slide.addText(
  [
    { text: 'where ' },
    { math: latexToOmml('x^2+1=y', { display: false }), inline: true },
    { text: ' holds' },
  ],
  { x: 1, y: 1, w: 8, h: 1 }
)

The equation is emitted as an <a14:m><m:oMath> run (no <m:oMathPara>) within the same paragraph as the surrounding runs. The Requires="a14" envelope stays at the shape level, exactly as for display math.

Scope and limits

  • No LaTeX preprocessing / macro packages: the input goes straight to temml. Custom macros, \usepackage, and environments temml does not support are out of scope.
  • No raster fallback: output relies on the Requires="a14" envelope, understood by PowerPoint 2010+. There is no mc:Fallback image for non-a14 consumers.
  • Fidelity is temml + mathml2omml's, with one correction applied in between. Accent commands (\hat, \bar, \vec, \ddot, …) used to render as <m:limUpp> (an over-limit, with limit spacing), because temml emits a bare <mover> and mathml2omml keys strictly off accent="true". latexToOmml now stamps that attribute, and swaps temml's spacing modifier (U+02C6, U+2192) for the combining mark ECMA-376 §22.1.2.20 says an accPr character should be (U+0302, U+20D7), so accents come out as <m:acc> with the character Word itself writes. This applies to latexToOmml only: mathmlToOmml passes your MathML through as written, because there the accent attribute is yours to set. Constructs that were already mapping well are untouched: \widehat and \overbrace stay <m:groupChr>, \overline/\underline stay <m:borderBox>, \stackrel stays <m:limUpp>. Two cases remain limits by necessity: \utilde and other under-accents (OMML has no under-accent object, and the symmetric accentunder="true" would move the mark above the base), and \ddddot, whose two-character operator has no single m:chr. See issue #6.

Error policy

Invalid LaTeX throws (with temml's parse position) rather than emitting a degenerate equation: consistent with the library's no-silent-coercion rule. Wrap calls in try/catch if you convert untrusted input.