Morphio
Morphs the font, so one word renders as another.
๐ฅ Installation
[!NOTE] You can try Morphio without installing it in the browser.
Using binstall
cargo binstall morphio
Downloading from Releases
Navigate to the Releases page and download respective binary for your platform. Make sure to give it execute permissions.
Compiling from Source
cargo install morphio
๐ Usage
๐ป CLI
Morphio: Morphs the font, so one word renders as another.
Options:
-i, --input input font file path
-o, --output output font file path
-r, --recipe load morph rules and word matching options from a TOML
recipe file, ignoring command-line options
-m, --no-word-match
disable both start and end word matching
--no-word-match-start
disable word matching at the start of the source word
--no-word-match-end
disable word matching at the end of the source word
--skip-missing-glyphs
skip rules that reference missing glyphs instead of failing
-y, --yes allow overwrite output file if it exists
-h, --help display usage information
Without a recipe file, pass rules as positional FROM TO pairs:
morphio -i input.ttf -o output.ttf banana orange from to
To relax word-boundary matching or skip unsupported rules:
morphio -i input.ttf -o output.ttf --no-word-match-end --skip-missing-glyphs banana orange
To drive the CLI from a recipe file:
morphio -i input.ttf -o output.ttf -r tests/recipes/simple.toml
๐ Web Interface
The browser demo supports:
- Uploading a font file
- Adding multiple morph rules
- Toggling advanced options:
- Match word start
- Match word end
- Skip missing glyphs
- Previewing original and morphed text side by side
- Downloading the morphed font
- Importing and exporting recipe TOML files
The web UI uses the same recipe format as the CLI and library.
๐งพ Recipes
Recipes are TOML files that store:
- Morph rules
- Word-boundary matching options
- Whether rules with missing glyphs should be skipped
Example:
[]
= true
= true
= false
[[]]
= "banana"
= "orange"
[[]]
= "from"
= "to"
Notes:
word_match_start = falseallows matches inside a longer word prefix, such as morphingxbananatoxorange.word_match_end = falseallows matches before a longer word suffix, such as morphingbananastooranges.skip_missing_glyphs = trueignores rules whose source or target characters are not present in the font instead of aborting the whole morph.
You can find example recipes under tests/recipes.
โ TODO
- Actual shaping tests via
harfrust(when it updates on crates.io to useread-fonts0.38.0) - Replace our rough implementation of TTC support after
write-fontsadds support for that. - Recipe (configuration) support
- Advanced settings
- Morph rules
- Skip rules with missing glyphs instead of failing
- Configure word matching of start and end of words separately
- Reduce TTC font sizes (table sharing?)
- Allow morphing multiple words in one go
- Allow morphing words with different lengths
- ServiceWorker
- Option for enabling/disabling word matching
- Say we want to morph "banana" to "orange"
- When word matching is enabled,
xbananawill not be morphed, because we're matching whole words, not letters - When word matching is disabled,
xbananawill be morphed toxorange
- Optimization
- Use
CoverageTable::Format2, which allows for more efficient storage of contiguous ranges of glyphs
- Use
- Better word matching
- Currently we consider whole words only by letters (
[a-zA-Z]+) - Next stage: consider digits (
[0-9]+) and underscores (_) - Maybe an option for toggling which characters to consider as part of words?
- Currently we consider whole words only by letters (
- Bug fixes
- Might not work with fonts with multiple language records, e.g.
IMPACT.TTF
- Might not work with fonts with multiple language records, e.g.
The following is of low priority, and may not get implemented:
- Reuse 1 -> N and N -> 1 mappings
- Determine "best split point", instead of just split in the end