LaTeXSwiftUI

repository·main·Indexed 18 days ago

https://github.com/colinc86/latexswiftui

A SwiftUI package for rendering high-quality TeX and LaTeX math-mode equations powered by MathJax. It supports inline and block equations, VoiceOver accessibility via the Speech Rule Engine (SRE), and CJK script scaling. The library provides a LaTeX view that integrates with SwiftUI layout and styling, as well as the ability to render equations directly to UIImage or NSImage. Requires Swift 6.0 and supports iOS 15+, macOS 12+, and visionOS 1+.

Tokens
2.9K
Snippets
12
Records
13
Agent score
14%

What's inside LaTeXSwiftUI

  1. Overview of LaTeXSwiftUI capabilities

    main

    LaTeXSwiftUI is a package that renders TeX and LaTeX equations using MathJaxSwift (powered by MathJax).

    Key Capabilities:

    • Renders inline and block math-mode equations.
    • Supports \text{} within equations.
    • Supports numbered block equations.
    • Supports various environments like \begin{align}, \begin{cases}, \begin{array}, etc.
    • Provides VoiceOver accessibility via the Speech Rule Engine (SRE).
    • Supports CJK and non-Latin script scaling via .script().
    • Automatically scales with system Dynamic Type settings.
    • Allows rendering to UIImage/NSImage without a SwiftUI view.

    Limitations:

    • Does not render full LaTeX documents.
    • Does not render text-mode macros (only math-mode macros).

    Requirements:

    • Swift 6.0
    • iOS 15+, macOS 12+, or visionOS 1+
  2. Install LaTeXSwiftUI via Swift Package Manager

    main

    Add the following dependency to your Swift Package Manager manifest file to include LaTeXSwiftUI in your project. Ensure you are using version 2.0.0 or later to access v2 features like accessibility and script scaling.

    .package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "2.0.0")
  3. Quick Start with the LaTeX view

    main

    To render LaTeX equations in SwiftUI, import LaTeXSwiftUI and use the LaTeX view. The view accepts a string containing TeX/LaTeX math-mode macros (e.g., using $ for inline math). Because the LaTeX view's body is composed of standard SwiftUI Text views, you can apply common modifiers like .fontDesign() and .foregroundColor() directly to it.

    import LaTeXSwiftUI
    
    struct MyView: View {
      var body: some View {
        LaTeX("Hello, $\\LaTeX$!")
          .fontDesign(.serif)
          .foregroundColor(.blue)
      }
    }
  4. Handle HTML entities and string formatting

    main

    LaTeX cannot parse raw HTML entities (e.g., <). Use .unencoded() to decode them.

    By default, the view renders Markdown syntax (*, **, ***, ~~, `, [...] (...)) and allows escaping reserved LaTeX characters (&, %, $, #, _, {, }, ~, ^, \) with a backslash.

    Use .ignoreStringFormatting() to disable both Markdown and escape replacement, or .processEscapes() to specifically allow \$ for literal dollar signs and \\ for literal backslashes.

    // Decode HTML entities like <
    LaTeX("$x^2<1$")
      .unencoded()
    
    // Disable Markdown and escape replacement
    LaTeX(input)
      .ignoreStringFormatting()
    
    // Allow literal $ and \ via escapes
    LaTeX(input)
      .processEscapes()
  5. Adjust equation scaling for non-Latin scripts

    main

    When displaying equations inline with non-Latin scripts (like CJK), equations may appear misaligned. Use .script(_:) to adjust the scaling:

    • .latin (default): Uses the font's x-height.
    • .cjk: Uses the font's cap-height (suitable for Korean, Japanese, and Chinese).
    • .custom(CGFloat): Multiplies the font's x-height by the provided factor.
    // For Korean or Japanese
    LaTeX("方程式 $E = mc^2$ は有名です。")
      .script(.cjk)
    
    // Custom scaling
    LaTeX("$\int_0^1 x^2 dx$")
      .script(.custom(1.3))
  6. Configure accessibility labels for equations

    main

    Rendered equations are images. Use .imageAccessibility(_:) to provide VoiceOver support:

    • .sre (default): Uses MathJax's Speech Rule Engine to generate natural language descriptions.
    • .input: Uses the raw TeX input as the label.
    • .none: No accessibility label (default SwiftUI behavior).
    • .custom(String): Uses a provided custom string.
    // Natural language (default)
    LaTeX("$x^2 + y^2 = z^2$").imageAccessibility(.sre)
    
    // Raw TeX
    LaTeX("$x^2 + y^2 = z^2$").imageAccessibility(.input)
    
    // Custom label
    LaTeX("$E = mc^2$").imageAccessibility(.custom("Einstein's mass-energy equivalence"))
  7. Configure image rendering and error modes

    main

    Image Rendering Mode

    Control how equations handle color via .imageRenderingMode(_:):

    • .template (default): Matches the surrounding text style.
    • .original: Displays the original colors defined in the LaTeX (e.g., \color{red}).

    Error Mode

    Control how rendering errors are handled via .errorMode(_:):

    • .original: Shows the original input text.
    • .error: Shows an error message.
    • .rendered: Shows a rendered image if available (loads noerrors and noundefined MathJax packages).
    // Match surrounding text color
    LaTeX("Hello, $\\color{red}\\LaTeX$!")
      .imageRenderingMode(.template)
    
    // Show original colors
    LaTeX("Hello, ${\\color{red} \\LaTeX}$")
      .imageRenderingMode(.original)
    
    // Error handling examples
    LaTeX("$\\asdf$").errorMode(.original)  // Show text
    LaTeX("$\\asdf$").errorMode(.error)     // Show error
    LaTeX("$\\asdf$").errorMode(.rendered)  // Show image if possible
  8. Render LaTeX equations to images directly

    main

    You can render LaTeX equations to UIImage (iOS/visionOS) or NSImage (macOS) without using the LaTeX SwiftUI view. This is useful for UIKit integration or image export.

    Use LaTeX.renderToImages(_:displayScale:processEscapes:). Each equation in the input string produces one image in the returned array.

    // Basic rendering
    let images = LaTeX.renderToImages("$x^2 + y^2 = z^2$")
    
    // Advanced rendering
    let images = LaTeX.renderToImages(
      "Euler's identity: $e^{i\\pi}+1=0$",
      displayScale: 3.0,
      processEscapes: true
    )
  9. Configure parsing modes and equation delimiters

    main

    The LaTeX view can either search for specific equation delimiters within a string or treat the entire input as a math expression.

    Supported Delimiters:

    • $ ... $
    • $$ ... $$
    • \( ... \)
    • \[ ... \]
    • \begin{equation} ... \end{equation}
    • \begin{equation*} ... \end{equation*}
    • \begin{name} ... \end{name} (Generic environments like align, gather, cases, array, matrix, etc., are automatically recognized as block equations).

    Use .parsingMode(_:) to switch between modes.

    // Only parse equations (default behavior)
    LaTeX("Euler's identity is $e^{i\\pi}+1=0$.")
      .parsingMode(.onlyEquations)
    
    // Parse the entire input as math
    LaTeX("\\text{Euler's identity is } e^{i\\pi}+1=0\\text{.}")
      .parsingMode(.all)
  10. Manage performance and caching

    main

    LaTeXSwiftUI caches both SVG data from MathJax and the resulting rasterized images.

    Clearing Caches:

    • LaTeX.dataCache.removeAllObjects(): Clears the SVG data cache.
    • LaTeX.imageCache.removeAllObjects(): Clears the rendered image cache.

    Preloading: To minimize lag when a view appears, call .preload() at the end of your modifier chain. This renders the equations in the background before they are needed in the UI.

    // Clear caches
    LaTeX.dataCache.removeAllObjects()
    LaTeX.imageCache.removeAllObjects()
    
    // Preload equations in a list
    ForEach(expressions, id: \.self) { expression in
        LaTeX(expression)
          .font(.caption2)
          .preload() // Must be called last
    }
  11. Configure rendering styles and animations

    main

    Rendering is performed off the main thread. Use .renderingStyle(_:) to control how the view behaves while waiting for MathJax to finish:

    • .wait (default): Blocks until rendering completes.
    • .empty: Remains empty until rendering completes.
    • .original: Displays the input text until rendering completes.
    • .redactedOriginal: Displays a redacted placeholder until rendering completes.
    • .progress: Displays a progress indicator until rendering completes.

    When using asynchronous styles (.original, .redactedOriginal, .progress), you can use .renderingAnimation(_:) to animate the transition.

    LaTeX(input)
      .renderingStyle(.original)
      .renderingAnimation(.easeIn)
  12. Configure fonts for LaTeXSwiftUI

    main

    The LaTeX view calculates equation sizing based on the font's x-height. To ensure correct sizing, use SwiftUI's preferred fonts or pass platform font types (UIFont/NSFont) directly.

    Warning: Do not use custom SwiftUI fonts created via .custom(name:size:) or .system(size:), nor wrap platform fonts in a SwiftUI Font() object, as this will cause incorrect equation sizing.

    // Recommended: SwiftUI preferred fonts
    LaTeX("Hello, $\\LaTeX$!")
      .font(.title)
    
    // Recommended: Platform font types passed directly
    LaTeX("Hello, $\\LaTeX$!")
      .font(UIFont.systemFont(ofSize: 30))
    
    LaTeX("Hello, $\\LaTeX$!")
      .font(UIFont(name: "Avenir", size: 25)!)