Metadata-Version: 2.4
Name: omml-converter
Version: 0.1.0
Summary: Convert OMML equations in .docx files to MathType OLE objects
Project-URL: Homepage, https://github.com/bohdanbodnarenko/omml-converter
Project-URL: Repository, https://github.com/bohdanbodnarenko/omml-converter
Project-URL: Issues, https://github.com/bohdanbodnarenko/omml-converter/issues
Project-URL: Changelog, https://github.com/bohdanbodnarenko/omml-converter/blob/main/CHANGELOG.md
Author-email: Bohdan Bodnarenko <bodya.bodnarenko@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: docx,equation,mathml,mathtype,office,omml,word
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business
Classifier: Topic :: Text Processing :: Markup
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: lxml>=6.1.0
Requires-Dist: olefile>=0.47
Description-Content-Type: text/markdown

# omml-converter

[![CI](https://github.com/bohdanbodnarenko/omml-converter/actions/workflows/ci.yml/badge.svg)](https://github.com/bohdanbodnarenko/omml-converter/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/omml-converter.svg)](https://pypi.org/project/omml-converter/)
[![Python versions](https://img.shields.io/pypi/pyversions/omml-converter.svg)](https://pypi.org/project/omml-converter/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Convert the math equations in a Microsoft Word `.docx` from **OMML** (Office Math
Markup Language, Word's native equation format) into embedded **MathType** OLE
objects (`Equation.DSMT6`) — without Word, MathType, or any Microsoft software
installed. Pure Python.

The original OMML is preserved as a fallback, so every equation stays visible in
ordinary Word while MathType-aware tooling can pick up the embedded objects.

## Why

Some publishers, journal submission systems, and downstream tools expect Word
documents whose equations are MathType objects rather than native Office math.
Producing those normally requires a Windows machine with MathType installed.
`omml-converter` does the conversion offline and cross-platform.

## Features

- **Pure Python**, no Word/MathType/COM dependency — runs anywhere.
- Converts a wide range of OMML constructs (see [below](#supported-constructs)).
- Keeps the original OMML as an `mc:AlternateContent` **fallback**, so equations
  never disappear in standard Word.
- Writes valid OLE Compound File Binary (CFB v3) streams and MTEF 5.0 content.
- Per-equation error isolation: one bad equation never aborts the whole file.

## Installation

```bash
pip install omml-converter
```

Or run it without installing, using [`pipx`](https://pipx.pypa.io/) or
[`uv`](https://docs.astral.sh/uv/):

```bash
pipx install omml-converter
# or
uvx omml-converter input.docx
```

Requires **Python 3.12+**.

## Usage

```bash
omml-converter input.docx
```

Writes `input_mathtype.docx` next to the input. Choose the output path with `-o`:

```bash
omml-converter input.docx -o converted.docx
omml-converter input.docx --verbose      # show each equation as it converts
omml-converter input.docx --quiet        # only print errors
omml-converter --version
```

### Options

| Option | Description |
| --- | --- |
| `input` | Input `.docx` file (required). |
| `-o`, `--output` | Output path (default: `<input>_mathtype.docx`). |
| `-v`, `--verbose` | Log every equation as it is converted. |
| `-q`, `--quiet` | Suppress progress; print errors only. |
| `--version` | Print the version and exit. |
| `-h`, `--help` | Show help and exit. |

### Exit codes

| Code | Meaning |
| --- | --- |
| `0` | Success — all equations converted (or none present). |
| `1` | Bad input (missing / non-`.docx` / unreadable) or one or more equations failed. |
| `2` | Invalid command-line arguments (from argparse). |

The output `.docx` is always written when the input is readable; equations that
fail to convert are left as their original OMML.

## Use as a library

```python
from omml_converter import convert

summary = convert("input.docx", "output.docx")
print(summary.found, summary.converted, summary.skipped, summary.errors)
```

## How it works

Each `m:oMath` equation is taken through a four-stage pipeline and embedded back
into the document:

```
.docx ──▶ OMML  ──▶  MathML  ──▶  MTEF 5.0  ──▶  OLE (CFB)  ──▶ .docx
        omml_to_   mathml_to_      mtef.py        ole.py      (re-zipped)
        mathml.py  mtef.py
```

1. **OMML → MathML** (`omml_to_mathml.py`) — parse Office math into standard MathML.
2. **MathML → MTEF** (`mathml_to_mtef.py`) — encode MathType 5.0 equation records.
3. **MTEF → Equation Native stream** (`mtef.py`) — wrap in the MTEF stream header.
4. **Equation Native → OLE** (`ole.py`) — build a minimal OLE Compound File.

The OLE object is inserted via `mc:AlternateContent`: a `Choice` requiring a
namespace Word doesn't recognise (so Word renders the OMML `Fallback`), while
MathType-aware tooling locates the embedded `Equation.DSMT6` object.

## Supported constructs

Fractions · radicals (square and nth root) · subscripts, superscripts and
sub-superscripts · n-ary operators (sum, product, integral) · functions ·
delimiters · accents and bars · matrices and equation arrays · phantoms and
boxes · Greek letters and common operators.

## Limitations

- Targets **MathType 5.0 / `Equation.DSMT6`** OLE objects specifically.
- Visual rendering of the OLE object requires a MathType-aware consumer; in
  plain Word the OMML fallback is what you see.
- Highly unusual or malformed OMML may be skipped (reported on stderr) rather
  than producing an incorrect object.

## Development

```bash
git clone https://github.com/bohdanbodnarenko/omml-converter.git
cd omml-converter
uv sync                       # create the venv and install dev deps
uv run pytest                 # run the test suite (with coverage)
uv run ruff check src tests   # lint
uv run ruff format src tests  # format
uv run mypy                   # type-check
uv run pre-commit install     # enable git hooks (optional)
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for details.

## Releasing

Tagging `vX.Y.Z` triggers `.github/workflows/release.yml`, which builds and
publishes to PyPI via [trusted publishing](https://docs.pypi.org/trusted-publishers/).
This requires a one-time PyPI publisher configuration for the repository.

## License

[MIT](LICENSE) © Bohdan Bodnarenko
