Registry / RepositoryTypeScriptRustPython
Rollpie
ReadmeFiles
Versions
Info
Download
0.4.01085.8 KB2026-10-160.3.21087.6 KB2026-10-160.3.11087.5 KB2026-10-160.3.0117.8 KB2026-10-160.2.1106.1 KB2026-10-150.2.0105.5 KB2026-10-15
Version
0.2.0
Copyright
Rollpie, Irohabook
Publisher
math
Published
2026-10-15
Size
105.5 KB
Downloads
19
Checksum
f438a48f6f2fc61d892f930eb4fb56fb5a8e302e733a8c3a6283d0ff7350cd08
Dependencies
rust/[email protected]
rust/[email protected]

README.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# hongo

A Rust library that typesets documents written in LaTeX into PDF.

It uses neither TeX nor LaTeX. Reading the source, breaking lines, laying out pages and writing the PDF
are all done here. Math goes to [suki](https://rollpie.com/rust/suki), and chemical structures go to
[lina](https://rollpie.com/rust/lina). Apart from these two, it depends on no crates.

It can set text that mixes Japanese and Latin script. It handles the spacing between Japanese
characters, the space between Japanese and Latin text, and the characters that may not begin or end
a line.

## Usage

```
cargo build --release
./target/release/hongo doc.tex
```

The PDF is written next to the document, with the same name and `.pdf`. Change it with `-o`.

```
./target/release/hongo doc.tex -o out.pdf
```

Fonts go in `font/`. The math typeface is looked up under the name `latinmodern-math.otf`.
For Japanese, the first file in `font/` that is not the math typeface is used. To choose a font for
each role, pass `--font-roman`, `--font-japanese` and so on. `--help` lists them.

It also works as a library.

```
use std::path::Path;

let library = hongo::font::open(
    Path::new("font/latinmodern-math.otf"),
    None, None, None, None, None,
    Some(Path::new("font/ipaexm.ttf")),
)?;
let source = std::fs::read_to_string("doc.tex")?;
let made = hongo::render(&source, &library, &hongo::Style::default(), Path::new("."))?;
std::fs::write("doc.pdf", made.data)?;
```

## Trying it in a browser

A small server comes with it. Paste a source and press the button, and it becomes a PDF that shows on
the page and can be saved.

```
cargo run --release --example serve
```

Open `http://127.0.0.1:7830`. It does not accept connections from other machines.
If there is no Japanese typeface in `font/`, pass one with `--font-japanese`.

```
cargo run --release --example serve -- --font-japanese /path/to/mincho.otf
```

`test/report.tex` is loaded at the start. Edit it and press the button to typeset it again.
If the source has a mistake, the page says on which line and what could not be read.

## Samples

They are in `test/`. `cargo run --example check` typesets all of them.

- `article.tex` - an article with math, tables, footnotes and references (3 pages)
- `report.tex` - a report with chapters, an appendix, floating figures, `p{}` columns and chemical structures (14 pages)
- `sample.tex` - one of each command (3 pages)
- `figure.tex` - images, floats and footnotes (2 pages)
- `feature.tex` - chapters, the appendix, alignment and nested lists (3 pages)

## What you need

Latin Modern Math (`latinmodern-math.otf`) is needed as the math typeface. It is the same file as in
suki's `font/`. Without it, neither math nor Latin text can be set.

To set Japanese, put a Japanese typeface in `font/`. IPAex Mincho and Noto Serif JP may be embedded
in PDF. Without one, Japanese characters do not appear, and hongo lists the missing characters at the end.

With the Latin Modern text faces (`lmroman10-regular.otf` and so on), body text is set in them.
Otherwise the Latin glyphs of the math typeface are used, and bold and italic are replaced by the math
alphanumeric characters (from U+1D400).

## Where it runs

It is written with the standard library only, so it runs wherever Rust does. It makes no OS-specific
calls. Sources with CRLF line endings are read too.

It has been checked on macOS only, not on Linux or Windows.

Only `examples/check.rs` looks for a macOS font when `font/` has no Japanese typeface. It exists for
local checks, and a font in `font/` is used first.

## Supported LaTeX

The document structure covers `\documentclass`, `\title`, `\author`, `\date`, `\maketitle`,
`\tableofcontents`, headings from `\part` to `\subparagraph`, and `\appendix`. `article` has no
chapters; `report` and `book` do. A chapter starts on a new page.

Font changes are `\textbf`, `\textit`, `\emph`, `\texttt`, `\textsf` and `\underline`, and
declarations such as `\bfseries`. Sizes run from `\small` to `\Huge`.

Environments are `itemize`, `enumerate`, `description`, `quote`, `quotation`, `center`, `flushleft`,
`flushright`, `verbatim`, `abstract`, `tabular`, `table`, `figure` and `thebibliography`.
Tables take `l`, `c`, `r` and `p{width}` columns, `|` rules, `\hline` and `\multicolumn`.

Math is `$…$`, `\(…\)`, `$$…$$`, `\[…\]`, `equation`, `align` and `gather`, with their starred forms.
suki sets the contents, including `aligned`, `split` and `gathered` inside a formula.
Chemical structures are `\chemfig` and `\chemname`, set by lina.

References are `\label`, `\ref`, `\pageref`, `\cite`, `\footnote` and `\caption`.
Images are `\includegraphics`, which reads `width`, `height` and `scale`. PNG and JPEG can be used.

You can define your own commands and environments. `\newcommand{\name}[number of arguments][default]{body}`
and `\newenvironment{name}[number of arguments]{begin}{end}` are read and expanded into the tokens.
plain TeX's `\def\name#1{body}` is read too. `\input` and `\include` are replaced by the contents of the file.

Furigana is added with `\ruby{漢字}{かんじ}`. The base text and the reading are centered on the wider
of the two. The reading is drawn in the space between lines, so the line spacing does not change.
The table of contents and the bookmarks show only the base text.

Some commands from common packages are read with a substitute. booktabs' `\toprule` and the like become
horizontal rules, and `\textcolor` drops the color and keeps the content.
`\fbox`, `\mbox`, `\rule`, `\eqref`, `\footnotemark`, `\footnotetext`, `minipage`, repeated columns
such as `*{3}{c}`, and accented letters such as `\'e` are read as well.

## How it works

Reading, layout and writing are kept apart.

`token` cuts the source into tokens, and `parse` builds a tree. The contents of math, chemical structures
and `verbatim` are kept as written, to be passed to suki and lina unchanged.

`number` numbers headings, figures, tables, equations and references, and ties each `\label` to its number.

`layout` turns the tree into a vertical list. `line` breaks body text into lines. When both edges are
justified, it chooses the breaks by looking at the whole paragraph; otherwise it fills each line as far
as it goes. Zero-width spaces sit between Japanese characters, so lines of Japanese alone are justified
the same way.

`page` lays the vertical list out on pages. A footnote is placed on the same page as the line that carries
it, and the room for body text shrinks accordingly. Floats go to the top of the first page where they fit.

`pdf` writes the file. Every character is set in a Type0 font with Identity-H, so glyph IDs can be written
directly. Glyphs with no character assigned (such as stretched delimiters) and Japanese are handled the
same way. ToUnicode is added so that text can be selected and copied.

The table of contents and `\pageref` cannot be written until page numbers are known, so layout runs twice.

## Decisions

No outside crates. Fonts are read with suki's code, and the PDF writer is written here.

Content streams are not compressed, so that no compressor has to be written; the files are larger for it.
Japanese typefaces are cut down to the glyphs used before they are embedded, so even a 20 MB typeface
ends up as a few hundred kilobytes.

PNG and JPEG are passed to the PDF without being decoded. PNG's IDAT is zlib, and so is PDF's
FlateDecode, so the data can go in as it is once the predictor parameters are copied over.
PNGs with transparency are not read, because separating the transparency would mean decoding the image.

## Not supported

There is no hyphenation for Latin text. Without hyphenation tables, a long word that does not fit
simply runs past the end of the line.

Kerning and ligatures are not applied, because the font's `kern` and `GPOS` tables are not read.

Two-column layout, marginal notes, indexes and reading references from `.bib` files are not supported.

## License

Dual licensed under MIT and Apache-2.0. Take whichever you prefer.

- [LICENSE-MIT](./LICENSE-MIT)
- [LICENSE-APACHE](./LICENSE-APACHE)