microtex

repository·master·Indexed 20 days ago

https://github.com/nanomichael/microtex

A dynamic, cross-platform, and embeddable C++ library for rendering LaTeX mathematical formulas as SVG images or within GUI applications. It supports advanced mathematical notation, multi-language text, tables, and decorative framing. The library provides both a high-level General Mode for simple parsing and a Builder Mode for granular control over alignment and sizing, as well as a headless CLI for batch or single SVG conversion.

Tokens
14K
Snippets
52
Records
63
Agent score
71%

What's inside microtex

  1. Implement the tex::Graphics2D interface

    master
    The tex::Graphics2D interface is the core of the graphical environment. All TeX drawing operations are performed on a Graphics2D context. You must implement this interface by wrapping your platform's specific 2D graphics API (e.g., Cairo on Linux, GDI+ on Windows) to support affine transformations and meta-graphical operations.
  2. Build the microtex demo

    master

    To build the demo, ensure you have a C++ compiler supporting the C++ 17 standard and CMake installed.

    Platform-specific dependencies:

    • Windows: CygWin or MinGW is recommended; Gdiplus is required.
    • Linux: GTKMM and GSVMM are required for GTK builds.
    • Qt: Qt development packages must be installed. To build in Qt mode, add -DQT=ON to the CMake command.

    Build steps:

    cd your/project/dir
    mkdir build
    cd build
    cmake ..
    make -j32

    After building, run the LaTeX executable in the build directory to launch the demo.

  3. Run microtex in headless mode (Batch and Single)

    master

    Microtex supports a headless mode (no GUI) on Linux that converts LaTeX code into SVG images.

    Batch Mode

    Use this mode to process multiple LaTeX snippets from a file. Snippets in the file should be separated by a line containing only the % character.

    ./LaTeX -headless \
        -samples=res/SAMPLES.tex \
        -outputdir=samples \
        -prefix=sample_ \
        -textsize=14 \
        -foreground=black \
        -background=white \
        -padding=0 \
        -maxwidth=720

    Single Mode

    Use this mode to convert a single string of LaTeX code into an SVG.

    ./LaTeX -headless \
        "-input=\sqrt[3]{(x-y)^3}=x-y" \
        -output=an_example.svg

    Note: If both -outputdir and -input are specified, the -input option takes precedence.

  4. Apply transformations with ScaleBox and RotateBox

    master

    Use DecorBox subclasses to apply geometric transformations to an existing box.

    • ScaleBox: Scales a box by a factor sx (horizontal) and sy (vertical), or a single uniform factor.
    • RotateBox: Rotates a box by a specified angle. You can specify the rotation origin using the Rotation enum.

    Rotation Origins

    Use the Rotation enum to define the pivot point:

    • bl, bc, br: Bottom Left, Center, Right
    • tl, tc, tr: Top Left, Center, Right
    • Bl, Bc, Br: Baseline Left, Center, Right
    • cl, cc, cr: Center Left, Center, Right
    • cc: Center Center
    // Scale a box by 2x
    auto scaled = std::make_shared<tex::ScaleBox>(base_box, 2.0f);
    
    // Rotate a box 45 degrees around its center
    auto rotated = std::make_shared<tex::RotateBox>(base_box, 45.0f, tex::Rotation::cc);
  5. Compose layouts with HBox and VBox

    master

    Microtex provides grouping classes to compose complex layouts from individual boxes.

    • HBox: Arranges child boxes in a horizontal row. It supports adding boxes at specific positions and defining _breakPositions for line breaking.
    • VBox: Arranges child boxes vertically, one above the other. It supports adding boxes with specific interline spacing.

    Both classes allow adding boxes via add(const sptr<Box>& box) or add(int pos, const sptr<Box>& box) for positional insertion.

    // Example of horizontal and vertical composition
    auto hbox = std::make_shared<tex::HBox>();
    hbox->add(some_box);
    
    auto vbox = std::make_shared<tex::VBox>();
    vbox->add(hbox);
  6. Handle scripts with ScriptsAtom and CumulativeScriptsAtom

    master

    Microtex provides two ways to handle scripts (subscripts and superscripts):

    1. ScriptsAtom: Represents a base atom with a subscript and a superscript attached. It allows setting the alignment (left or right).
    2. CumulativeScriptsAtom: Used for building up multiple scripts. You can use addSuperscript(atom) and addSubscript(atom) to stack scripts onto a base atom.
    // Using ScriptsAtom
    auto scripts = std::make_shared<tex::ScriptsAtom>(base, sub, sup, true); // true for left alignment
    
    // Using CumulativeScriptsAtom for stacking
    auto cumulative = std::make_shared<tex::CumulativeScriptsAtom>(base, sub, sup);
    cumulative->addSuperscript(extraSup);
  7. How RowAtom and Dummy work together for layout

    master

    In microtex, a RowAtom represents a horizontal sequence of atoms separated by glue. Because TeX algorithms may change an atom's type (e.g., changing a bin atom to an ordinary atom) or replace a character atom with a ligature during the box creation process, the system uses a Dummy object to manage these transient changes.

    When a RowAtom is being processed via createBox, it uses a Dummy to wrap the atom that precedes its first child. This ensures that any modifications to the atom's state (like its AtomType or whether it is a textSymbol) are localized and can be reset, preventing permanent side effects on the original Formula structure.

    Row is an interface implemented by RowAtom that allows nested composed atoms to communicate with their predecessors via setPreviousAtom to correctly calculate glue and spacing.

  8. Add visual decorations with ColorBox and FramedBox

    master

    Decorate boxes with colors or frames:

    • ColorBox: Applies a foreground (fg) and background (bg) color to a box.
    • FramedBox: Wraps a box in a square frame. You can configure _thickness, _space (padding), _line (border color), and _bg (background color).
    • OvalBox: A specialized FramedBox that renders an oval frame instead of a square one.
    • ShadowBox: A specialized FramedBox that adds a shadow effect based on a shadowRule value.
    // Create a framed box with a blue border and yellow background
    auto framed = std::make_shared<tex::FramedBox>(base_box, 1.0f, 2.0f, color_blue, color_yellow);
    
    // Create an oval box
    auto oval = std::make_shared<tex::OvalBox>(framed_box_ptr);
  9. How Atoms and Boxes work in microtex

    master

    In microtex, an Atom is an abstract logical mathematical construction that eventually becomes a concrete, paintable Box.

    To use the Atom system for custom mathematical symbols, you must implement two key aspects:

    1. Box Creation: Implement createBox(Environment& env). This method transforms the logical unit into a Box using the provided Environment (which contains settings like TeX style, font, and color).
    2. Glue Determination (Types): Atoms define their AtomType to determine how much 'glue' (spacing) is used between them when placed in a row.
      • Simple Atoms: Most atoms have a single type. You can set this via the _type field (defaults to AtomType::ordinary).
      • Composite Atoms: For atoms composed of multiple child atoms in a row, you should override leftType() and rightType(). The leftType() determines the glue between this atom and the preceding one, while rightType() determines the glue between this atom and the following one.

    Additionally, atoms can specify _limitsType (for handling limits like superscripts/subscripts) and _alignment.

    // Conceptual implementation pattern for a custom Atom
    class MyCustomAtom : public tex::Atom {
    public:
      MyCustomAtom() {
        _type = tex::AtomType::ordinary;
      }
    
      // Transform logical atom to a concrete box
      virtual tex::sptr<tex::Box> createBox(tex::Environment& env) override {
        // Implementation logic to return a Box
      }
    
      // Allow cloning
      __decl_clone(MyCustomAtom)
    };
  10. Configure compile-time options

    master

    You can customize the build using CMake flags to reduce library size or assist in debugging:

    • HAVE_LOG: (Default: ON) If defined, the program outputs runtime logs (e.g., symbol parse results, box trees). Set to OFF for release builds.
    • GRAPHICS_DEBUG: (Default: ON) If defined, enables egin{debug} and egin{undebug} commands in LaTeX to draw box bounds and depth information.
    • MEM_CHECK: (Default: OFF) If defined, implements an empty graphics interface. This is used for memory leak detection with valgrind.

    Example Valgrind setup:

    cmake -DCMAKE_BUILD_TYPE=Debug -DGRAPHICS_DEBUG=ON -DMEM_CHECK=ON -DHAVE_LOG=OFF ..
    make -j32
    valgrind --leak-check=full -v ./LaTeX
  11. Understand the Box abstraction for layout

    master

    In microtex, a Box is an abstract graphical representation of a formula or element that can be painted. It uses three primary dimensions for layout calculations: _width, _height, and _depth.

    Key characteristics:

    • Fixed Dimensions: Most boxes have fixed character sizes and positions, though special Glue boxes may stretch or shrink.
    • Metrics: Layout is driven by the box's width, height, depth, and a _shift value (the meaning of which depends on the specific box type, such as up, down, left, or right).
    • Rendering: Subclasses must implement the draw(Graphics2D& g2, float x, float y) method to define how the box is painted.
    • Font Tracking: The lastFontId() method is used to determine the last font used within the box, which is critical for subsequent layout steps.
  12. Render multi-language text and character sets

    master

    MicroTeX can render various scripts and character sets within math or text modes:

    • Cyrillic and Greek: Supports alphabets like Russian, Greek, Bulgarian, Serbian, Ukrainian, and Belarusian.
    • Font Styles: Supports \mathbf (bold), \mathit (italic), \mathsf (sans-serif), and \mathtt (monospaced).
    • Colors: Text can be colored using \textcolor{color_name}{text} or \fcolorbox{border_color}{background_color}{text}.
    • ASCII/Unicode: Handles standard ASCII and extended character ranges.
    \begin{array}{lr}
      \mbox{\textcolor{Blue}{Russian}}&\mbox{\textcolor{Melon}{Greek}}\\
      \mbox{привет мир}&\mbox{γειά κόσμο}
    \end{array}