Equations converted between MathML, OMML (Word), MTEF (MathType and Equation Editor 3.0), UnicodeMath (Word's linear format) and LaTeX, in .NET, with MathML as the common representation.
| Format | Read | Write |
|---|---|---|
| MathML (presentation; Content MathML is read as the presentation it is written as) | ✓ | ✓ |
OMML (Office Math Markup Language, the equations of .docx) |
✓ | ✓ |
| MTEF (MathType, Equation Editor 3.0) | ✓ | |
| UnicodeMath | ✓ | ✓ |
| LaTeX (standard, or as Word writes it) | ✓ | ✓ |
SharpEquations targets .NET Standard 2.0 and .NET 10, and depends on nothing but the .NET base library (and System.Memory on .NET Standard 2.0).
using SharpEquations;
var equation = Equation.Parse(@"\frac{a^2+b^2}{c}", EquationFormat.LaTeX);
string unicodeMath = equation.ToString(EquationFormat.UnicodeMath); // (a^2+b^2)/c
XElement omml = equation.ToOmml();
string mathML = equation.ToString();
string latex = $"{equation:L}";
string converted = EquationConverter.Convert("x=(-b±√(b^2-4ac))/2a", EquationFormat.UnicodeMath, EquationFormat.LaTeX);EquationOptions sets the display mode, strict reading, whether formatting is kept, the LaTeX flavor (standard, or
the LaTeX of Word's equation editor) and LaTeX macros. An MTEF equation is read from the bytes of the "Equation Native"
stream of its OLE object (Equation.Parse(bytes, EquationFormat.Mtef)); reading the OLE object is left to the caller.
Equations compare by their normalized MathML: an equation written in its own format (UnicodeMath, OMML) reads back to the same equation, and one written in another format loses only what that format cannot hold.
SharpEquations.Avalonia is a real-time equation editor in the manner of the RichEditBox of WinUI in math mode and of
the equations of Word: UnicodeMath or LaTeX typed at the caret builds up into the equation when a space or an operator
ends an argument (a/b␣ becomes a fraction, \alpha␣ α), the caret moves through the slots of the structures, and the
equation is read and written as MathML or as an Equation.
<sharp:MathEditBox xmlns:sharp="using:SharpEquations.Avalonia" FontSize="28" InputFormat="UnicodeMath" Equation="{Binding Equation}" />var editor = new MathEditBox { InputFormat = EquationFormat.LaTeX };
editor.EquationChanged += (_, e) => Console.WriteLine(e.Equation?.ToString(EquationFormat.MathML));
string mathML = editor.GetMath(); // as RichEditTextDocument.GetMath
editor.SetMath(mathML); // as RichEditTextDocument.SetMath
editor.ViewMode = MathViewMode.Linear; // the equation as one line of UnicodeMath (Ctrl+Shift+L)
editor.EquationNumber = "(1)"; // at the right of the line, as #(1) or \tag{1}
string latex = editor.GetSelectedText(EquationFormat.LaTeX)!;
editor.CopyTextFormat = EquationFormat.MathML; // Ctrl+C pastes as an equation into Word
editor.Editor.InsertLineBreak(); // Shift+Enter: lines aligned at &
editor.Editor.InsertTableRow(); // and columns, in the matrix of the caretTyping \ and the start of a command opens a floating bar at the caret with its completions
(EquationCommands.Complete("al", EquationFormat.UnicodeMath) gives them from the core); the bar also offers structures
for the selection, the commands of a table and quick symbols.
The packages are SharpEquations.Avalonia (the controls), SharpEquations.Rendering and SharpEquations.Editing, with
the version of SharpEquations.
MathView shows an equation without editing it. Both lay out MathML after MathML Core with the OpenType MATH table of
a math font: Cambria Math on Windows, and Libertinus Math (SIL Open Font License), embedded, elsewhere. The editor is
three projects, so that the core keeps no dependency: SharpEquations.Editing (the editing model, no user interface),
SharpEquations.Rendering (the layout, no user interface) and SharpEquations.Avalonia (the controls). The design is in
docs/EDITOR.md; samples/SharpEquations.Avalonia.Demo is a window with the editor and its MathML,
UnicodeMath and LaTeX, and samples/SharpEquations.Avalonia.Browser.Demo the same demo in the browser, on WebAssembly
(published to GitHub Pages from main; to run it locally: dotnet workload install wasm-tools, then
dotnet run --project samples/SharpEquations.Avalonia.Browser.Demo). samples/SharpEquations.Avalonia.MathTools.Demo is a
second app around the editor, a set of math tools (a scientific keypad that types into the editor and computes what is
typed with AngouriMath, a library of formulas, a unit converter, a
solver of triangles), with
samples/SharpEquations.Avalonia.Browser.MathTools.Demo in the browser (published under math/ of the same site); what
they compute is in samples/SharpEquations.MathTools.Core and samples/SharpEquations.MathTools.Graphing, which have
no user interface.
How the conversions work, format by format, and how round trips are kept exact: docs/ARCHITECTURE.md.
dotnet build SharpEquations.slnx
dotnet test --solution SharpEquations.slnxThe tests use TUnit; they run on .NET 10 against the .NET 10 build, and against the .NET
Standard 2.0 build on .NET 8 (Linux, macOS) or on .NET Framework 4.8.1 (Windows). Their data is in tests/data (see
its README).
CI (.github/workflows/ci.yml) tests every push and pull request on Linux (.NET 10 and .NET 8), Windows (.NET 10 and
.NET Framework 4.8.1) and macOS (.NET 10), and packs the NuGet packages (the converter and the three of the editor, with one version). The release version is VersionPrefix in BuildVersion.props: bump it, and merging to
main tags vX.Y.Z, creates the GitHub release with the package attached, and publishes it to GitHub Packages and to
nuget.org (with Trusted Publishing: the repository
variable NUGET_USER names the nuget.org account; without it nuget.org is skipped). A push that keeps the version on
purpose says [no-new-version] in its commit message. Every pull request gets a pr-<N>-… pre-release, with the
package versioned X.Y.Z-pr.<N>.<run>, replaced on each push and deleted when the pull request closes. Dependabot keeps
the GitHub Actions current and Renovate the NuGet dependencies.
MIT (see LICENSE). Third-party files (the TEI stylesheets, the ports of UnicodeMathML and of the mathtype gem, the
code Parlot generates, test data) keep their licences: see NOTICE.