MathJaxSwift converts and renders math expressions in Swift by incorporating MathJax[^1] source code and using the JavaScriptCore framework. It wraps the MathJax conversion processes in convenient JavaScript methods described here and exposes them to Swift without using WebKit.
[^1]: MathJaxSwift is not affiliated with MathJax or any of its related entities.
Import the package, create a MathJax instance, and convert an input string to a supported output format.
import MathJaxSwift
do {
let mathjax = try MathJax()
let svg = try mathjax.tex2svg("\text{Hello}, \TeX{}!")
}
catch {
print("MathJax error: \(error)")
}
The example above converts the TeX input to SVG data that renders the following PNG. See the example section for more details.
🧰 Available Methods
MathJaxSwift implements the following methods to convert TeX, MathML, and AsciiMath to CommonHTML, MathML and SVG data.
Method
Input Format
Output Format
tex2chtml
TeX
cHTML
tex2mml
TeX
MathML
tex2svg
TeX
SVG
mml2chtml
MathML
cHTML
mml2svg
MathML
SVG
am2chtml
AsciiMath
cHTML
am2mml
AsciiMath
MathML
🧵 Threading and Memory
Initializing an instance of MathJax should not be performed on the main queue to prevent blocking of the UI. You should also attempt to keep a single reference to an instance and submit your function calls to it instead of creating a new MathJax instance each time you need to convert.
MathJaxSwift loads all of the necessary JavaScript in to its context to run all of the conversion methods. In the case that you only want to utilize a subset of the package’s output formats, you can instruct the MathJax instance to only initialize with your preferred output formats.
do {
// Save some time and don't load the SVG output format.
let mathjax = try MathJax(preferredOutputFormats: [.chtml, .mml])
}
catch {
print("Error initializing MathJax: \(error)")
}
The benefit of this approach is that, instead of loading all of the necessary JavaScript in to the instance’s context upon initialization, it loads the preferred output formats immediately, and then lazily loads any JavaScript in the future that may be required to execute a conversion method.
do {
// We _think_ we only need CommonHTML, so save some time by only loading that
// output format.
let mathjax = try MathJax(preferredOutputFormat: .chtml)
// It's ok to call `tex2mml` even though we set our preferred output format to
// `chtml`!
let mml = try mathjax.tex2mml("\text{Hello}, \TeX{}!")
}
catch {
print("MathJax error: \(error)")
}
Document options let you control the document created by MathJax. They apply to every conversion method and let you specify MathJax document-specific options.
// Add to the `skipHtmlTags` array.
var docOptions = DocumentOptions()
docOptions.skipHtmlTags.append("example")
// Process the input using the new options
let output = try! tex2chtml("\text{Hello, }$\LaTeX$\text{!}", documentOptions: docOptions)
Conversion Options
These options, as with document options, apply to to every conversion method. Although, the options’ display property only pertains to methods that take TeX input. They let you set input conversion options such as em and ex sizes, container and line widths, and scale.
// Process the TeX input as a block instead of inline
let convOptions = ConversionOptions(display: true)
let output = try! tex2chtml("\text{Hello, }$\LaTeX$\text{!}", conversionOptions: convOptions)
Processor Options
The input and output of each of the conversion methods is configurable through various processor options. For example, if you are calling the tex2svg conversion method, then you can configure the input and output with TexInputProcessorOptions and SVGOutputProcessorOptions, respectively.
let inputOptions = TexInputProcessorOptions(processEscapes: true)
let outputOptions = SVGOutputProcessorOptions(displayIndent: 0.5)
let svg = try! mathjax.tex2svg("\text{Hello, }\LaTeX\text{!}", inputOptions: inputOptions, outputOptions: outputOptions)
🚨 Error Handling
Each of the conversion methods are throwing methods, but you can also catch errors from MathJax using options.
let documentOptions = DocumentOptions { doc, math, err in
// Do something with the compile error...
}, typesetError: { doc, math, err in
// Do something with the typeset error...
}
let inputOptions = TexInputProcessorOptions { jax, err in
// Do something with the TeX format error...
}
♾️ MathJax Version
To check the version of MathJax that has been loaded, use the static metadata() throws method.
do {
let metadata = try MathJax.metadata()
print(metadata.version)
}
catch {
print("Error getting MathJax version: \(error)")
}
You can also use the returned metadata to check the MathJax node module’s URL and its SHA-512.
📗 Example
The following example class shows how to
create a MathJax instance,
set the preferred output to SVG,
create input, output and conversion options,
and render the SVG output string from TeX input.
class EquationRenderer {
// A reference to our MathJax instance
private var mathjax: MathJax
// The TeX input processor options - load all packages.
private let inputOptions = TeXInputProcessorOptions(loadPackages: TeXInputProcessorOptions.Packages.all)
// The SVG output processor options - align our display left.
private let outputOptions = SVGOutputProcessorOptions(displayAlign: SVGOutputProcessorOptions.DisplayAlignments.left)
// The conversion options - use block rendering.
private let convOptions = ConversionOptions(display: true)
init() throws {
// We only want to convert to SVG
mathjax = try MathJax(preferredOutputFormat: .svg)
}
/// Converts the TeX input to SVG.
///
/// - Parameter texInput: The input string.
/// - Returns: SVG file data.
func convert(_ texInput: String) async throws -> String {
return try await mathjax.tex2svg(
texInput,
conversionOptions: convOptions,
inputOptions: inputOptions,
outputOptions: outputOptions)
}
}
To use the class you could do something like:
let renderer = try EquationRenderer()
let svg = try await renderer.render("$\text{Hello, }\TeX$!")
📘 Documentation
The classes unique to this package (namely MathJax) should be well documented. Documentation about the MathJax options and conversion processes is not included.
To get around the limitations of the JSContext class, the package uses Webpack to create bundle files that can be evaluated by the context. The wrapper methods, MathJax, and Webpack dependencies are bundled together in an npm module called mjn.
mjn‘s main entry point is index.js which exposes the converter classes and functions that utilize MathJax. The files are packed with Webpack and placed in to the mjn/dist/ directory. chtml.bundle.js, mml.bundle.js, and svg.bundle.js files are loaded by the Swift package’s module and evaluated by a JavaScript context to expose the functions.
After making modifications to index.js, it should be rebuilt with npm run build executed in the mjn directory which will recreate the bundle files.
MathJaxSwift
MathJaxSwift
converts and renders math expressions in Swift by incorporating MathJax[^1] source code and using the JavaScriptCore framework. It wraps the MathJax conversion processes in convenient JavaScript methods described here and exposes them to Swift without usingWebKit
.[^1]:
MathJaxSwift
is not affiliated with MathJax or any of its related entities.📦 Installation
Add the dependency to your package manifest file.
🎛️ Usage
Import the package, create a
MathJax
instance, and convert an input string to a supported output format.🧰 Available Methods
MathJaxSwift implements the following methods to convert TeX, MathML, and AsciiMath to CommonHTML, MathML and SVG data.
tex2chtml
tex2mml
tex2svg
mml2chtml
mml2svg
am2chtml
am2mml
🧵 Threading and Memory
Initializing an instance of
MathJax
should not be performed on the main queue to prevent blocking of the UI. You should also attempt to keep a single reference to an instance and submit your function calls to it instead of creating a newMathJax
instance each time you need to convert.Each of the methods are also available with an
async
implementation.You can specify which queue to execute on when calling async methods. The instance will use the
.global()
queue by default.Preferred Output Formats
MathJaxSwift loads all of the necessary JavaScript in to its context to run all of the conversion methods. In the case that you only want to utilize a subset of the package’s output formats, you can instruct the
MathJax
instance to only initialize with your preferred output formats.The benefit of this approach is that, instead of loading all of the necessary JavaScript in to the instance’s context upon initialization, it loads the preferred output formats immediately, and then lazily loads any JavaScript in the future that may be required to execute a conversion method.
See the Notes section for more details.
⚙️ Options
Document Options
Document options let you control the document created by MathJax. They apply to every conversion method and let you specify MathJax document-specific options.
Conversion Options
These options, as with document options, apply to to every conversion method. Although, the options’
display
property only pertains to methods that take TeX input. They let you set input conversion options such asem
andex
sizes, container and line widths, andscale
.Processor Options
The input and output of each of the conversion methods is configurable through various processor options. For example, if you are calling the
tex2svg
conversion method, then you can configure the input and output withTexInputProcessorOptions
andSVGOutputProcessorOptions
, respectively.🚨 Error Handling
Each of the conversion methods are throwing methods, but you can also catch errors from MathJax using options.
♾️ MathJax Version
To check the version of MathJax that has been loaded, use the static
metadata() throws
method.You can also use the returned metadata to check the MathJax node module’s URL and its SHA-512.
📗 Example
The following example class shows how to
MathJax
instance,SVG
,To use the class you could do something like:
📘 Documentation
The classes unique to this package (namely
MathJax
) should be well documented. Documentation about the MathJax options and conversion processes is not included.Please refer to the official MathJax Documentation for more information.
📓 Notes
To get around the limitations of the
JSContext
class, the package uses Webpack to create bundle files that can be evaluated by the context. The wrapper methods, MathJax, and Webpack dependencies are bundled together in an npm module calledmjn
.mjn
‘s main entry point isindex.js
which exposes the converter classes and functions that utilize MathJax. The files are packed with Webpack and placed in to themjn/dist/
directory.chtml.bundle.js
,mml.bundle.js
, andsvg.bundle.js
files are loaded by the Swift package’s module and evaluated by a JavaScript context to expose the functions.After making modifications to
index.js
, it should be rebuilt withnpm run build
executed in themjn
directory which will recreate the bundle files.