LaTeX → HTML (tex4ht/make4ht/lwarp/LaTeXML)

2023 年 12 月,arXiv 开始为收到的论文提供 HTML 版本。这个三十多年只发 PDF 的预印本服务器改变做法的理由是可访问性,承担转换工作的是 LaTeXML。把 LaTeX 变成 HTML 还有别的办法——make4httex4ht)、lwarppandoc——而选择其实只取决于一个问题:这个工具是真的运行 TeX 引擎,还是自己去解析 LaTeX? 答案一旦确定,其余的事情就都随之而定:自定义宏能不能通过,公式是变成 MathML 还是图片,TikZ 图形又会变成什么。

LaTeX → HTML 的转换器只有两大类

一类是运行 TeX的:tex4ht(前端为 make4ht)和 lwarp 属于这一类。另一类是自己解析 LaTeX的:LaTeXMLpandoc 在这边。这个区别不是实现风格问题,它直接决定转换质量。运行 TeX 的一方让 TeX 自己去展开你写的 \newcommand,所以自定义宏和冷门宏包大多能通过;代价是要用一种相当别扭的手法——从排版过程的侧面观察并据此拼出 HTML——工具链因此很重。自己解析的一方快、输出整洁、语义标记做得好,但不认识的命令就是不认识。arXiv 选择 LaTeXML,是因为它要把投稿 LaTeX 的语义结构(定理、引用、公式的结构)原样带进 HTML 和 MathML,而不是为了还原版面的样子。

工具是否运行 TeX默认的公式输出获取方式
make4ht是,经由 htlatex行内为 HTML,行间为 SVG 图片TeX Live 自带
lwarp是,跑两条 pdflatex 构建线SVG 图片;加 mathjax 选项则用 MathJaxTeX Live 自带
latexml否,Perl 解析器MathMLPerl 程序;不属于 TeX Live
pandoc否,先落到自己的 AST--mathml--mathjax 选择Haskell 程序;不属于 TeX Live

make4ht 与 tex4ht:从侧面偷看排版的发明

如果你手上已经有一份文档,只想拿到 HTML,第一步应当是 make4ht file.tex。不需要额外安装,TeX Live 自带。它的做法相当大胆:tex4ht 让 TeX 照常排版这份文档,同时通过混入 DVI 流的钩子一路吐出 HTML 标签。因此能编译的文档大多也能转换——包括你自己用 \newcommand 定义的命令,因为展开由 TeX 完成,转换器根本不必知道它们存在。用一份定义了 \newcommand{\stress}[1]{\textbf{\itshape #1}} 的测试文件跑过去,HTML 里确实出现了粗斜体的 span。tex4ht 出自 Eitan Gurari(1947–2009,俄亥俄州立大学)之手,从 1996 年起由他一人维护。2009 年他骤然离世后,Michal Hoftich、Karl Berry 等人接手。TeX Live 2024 里附带的 README 至今写着:这里的文档由原作者 Gurari 撰写,在他去世后只做过很少的改动。

terminal
# the friendly front-end: HTML5 by default, no options needed
make4ht file.tex

# the classic driver, still what make4ht calls underneath
htlatex file.tex "html5,charset=utf-8" " -cunihtf -utf8"

直接敲 htlatex 的写法在旧文里很常见,但现在的定式是 make4ht。它是 Michal Hoftich 用 Lua 写的构建前端:默认输出 HTML5,一条命令还能顺带跑 bibtex 或 makeindex、对生成的 HTML 做后处理、转换图片,更细的调整可写进 Lua 构建文件。即便如此,tex4ht 的输出有时读起来不像 HTML,倒像是用 HTML 临摹了一遍排版结果。原因是默认情况下 TeX 的字体名会直接变成 CSS 类——正文里会看到 cmr-12cmmi-10 这类名字——所以若要放到网上,最好一开始就打算替换 doc.css 或在后面覆盖自己的样式表。各宏包的转换规则写在 .4ht 配置文件里,TeX Live 2024 的 tex4ht 带了 496 个。

公式:MathML、图片,还是 MathJax

直接跑 make4ht file.tex,行内公式会变成 HTML 文本,行间公式会变成 SVG 图片。在 TeX Live 2024 上实测,$f\colon \R \to \R$ 输出为含 的普通文字,而 \begin{equation} 的内容变成了名为 doc0x.svg 的图片,alt 属性里放着该公式的 ASCII 近似。这个默认值虽能读,但放大后发糊、无法复制、也搜不到。如果公式才是文档的主角,就该用选项改变输出。make4ht -u file.tex "mathml" 会把行间公式也变成 MathML,最后只剩 TikZ 图形还是图片。make4ht -u file.tex "mathjax" 则把公式以 LaTeX 原样嵌进 HTML,并在 head 里放入 window.MathJax 配置和 MathJax 3 的加载脚本。

terminal
# display math as an SVG image (the default)
make4ht file.tex

# display math as MathML — only TikZ pictures stay images
make4ht -u file.tex "mathml"

# leave the math as LaTeX and let MathJax 3 render it in the browser
make4ht -u file.tex "mathjax"

这里有一个只有选 mathjax 的人才会踩的坑:自定义宏不会被展开。 MathML 与图片都是 TeX 排版之后的结果,\newcommand 自然早已展开;而 mathjax 模式是把公式按源码原样写出去。实测中,定义了 \newcommand{\R}{\mathbb{R}} 的文档,其 HTML 里原封不动地出现 \(f\colon \R \to \R \),而且一条 \newcommand 定义都没有一起写出来。浏览器里的 MathJax 不认识 \R,于是这一处就变成红色的未定义错误。补救办法是在 MathJax 配置里重写同样的宏(window.MathJax 中的 tex.macros)。反过来说,大量使用自定义宏的文档,用 mathml 更安全——从可访问性看也是如此,屏幕阅读器能读 MathML,读不了图片。

lwarp:把 HTML 排进 PDF,再用 pdftotext 取出来

Brian Dunn 的 lwarp 从完全不同的角度解决同一个问题。它借用的是 LaTeX 自身的输出机制:让 pdflatex 把 HTML 源码当作正文排版,再用 pdftotext 从生成的 PDF 里把文字抽回来写成 .html。这确实就是它的做法——翻开 TeX Live 里的 lwarpmk.lua,可以找到调用 pdftotext -enc UTF-8 -nopgbrk -layout 的那一行。本地一份只有四节的测试文档,用于生成 HTML 的中间 PDF 就有 16 页。这样绕远是有理由的:LaTeX 的交叉引用、目录、索引和文献机制可以原样使用。lwarp 为它支持的每个宏包都准备了 HTML 侧的替代实现,TeX Live 2024 中共有 593 个 lwarp-*.sty

latex
% lwarp must be loaded BEFORE anything that pulls in color, graphics or hyperref
\documentclass{article}
\usepackage{lwarp}
\usepackage{amsmath,amssymb}
\usepackage{tikz}
\usepackage{hyperref}

% repeat your own macros for MathJax mode:
% \CustomizeMathJax{\newcommand{\R}{\mathbb{R}}}
terminal
pdflatex doc.tex     # first pass writes lwarpmk.conf and doc_html.tex
lwarpmk html         # build the HTML
lwarpmk limages      # render the math and picture images

真正跑起来后第一个撞上的是加载顺序。把 \usepackage{lwarp} 放在 tikz 之后,编译就停在 ! Package lwarp Error: Package color, or one which uses color, must be loaded after Lwarp.。lwarp 必须先于几乎所有宏包加载——这也是把它接到现成文档上的最大障碍。公式默认变成 SVG 图片,但 alt 属性里原样放着 LaTeX 源码,元素还带 role="math"(改用 \usepackage[mathjax]{lwarp} 就切到 MathJax,自定义宏用 \CustomizeMathJax 补上)。图片由单独一步 lwarpmk limages 生成,内部依次运行 pdfseparatepdfcroppdftocairo -svg——正是本站「导出为图像」那一页所讲的同一条流水线。

LaTeXML 与 arXiv 的 HTML 版

LaTeXML 是 Bruce Miller 在美国国家标准与技术研究院(NIST)开发的 Perl 转换器,它先把 LaTeX 落成语义 XML,再输出 HTML5 加 MathML、ePub、JATS 等。处理分两段:latexml 生成 XML,latexmlpost 把它转成 HTML。这种分工把「解析」和「呈现」拆开,同一份 XML 可以产出多种格式。arXiv 自 2023 年 12 月起提供 HTML 版,正是这一脉络的延续——更早的 arXivLabs 项目 ar5iv 已经用 LaTeXML 把整个语料转成过 HTML。若文档公式多、又重视语义结构与可访问性,它是首选。但 LaTeXML 不包含在 TeX Live 里。 它需要作为 Perl 发行包另行安装;撰写本文所用的机器上并没有 latexml,因此上面的两段式描述依据的是官方文档,而非本地实测。

terminal
# LaTeXML is a separate Perl install, not part of TeX Live
latexml --dest=file.xml file.tex
latexmlpost --dest=file.html file.xml   # HTML5 + MathML

自定义宏和 TikZ 到底能通过多少

说实话:倚重自定义宏和 TikZ 的文档不会转得干净。 就自定义宏而言,运行 TeX 的那一类(tex4ht、lwarp)占优——TeX 会先展开,转换器根本看不到原来的命令。但展开留下的是「粗体」「斜体」这类外观指令,不是含义,所以不会生成语义标签。\newcommand{\keyterm}[1]{\textbf{#1}} 只会得到相当于 <b> 的结果,永远不会是 <dfn>。TikZ 需要更干脆的妥协:tex4ht 和 lwarp 得出同一个结论——把图当作图片贴进去。本地实验里,TikZ 绘制的图变成了一张名为 doc0x.svg 的 SVG,alt 里只是把节点标签串在一起。如果你想要在 HTML 里真有意义的图,与其指望转换器,不如把图单独导出并亲手写 alt,那反而更快。

该选哪一个——按用途给结论

  • 只想要 HTML,不想再装环境make4ht file.tex。TeX Live 自带,不改文档就能跑。
  • 希望公式是 MathML(利于朗读、搜索和缩放)→ make4ht -u file.tex "mathml",或 LaTeXML。
  • 需要尽量保留 LaTeX 功能的正式网页版lwarp;前提是该文档能把 \usepackage{lwarp} 放在最前面。
  • 想做 arXiv 那样的语义化 HTML 论文LaTeXML(Perl,需在 TeX Live 之外另行安装)。
  • 源本来就是 Markdown,输出轻一点也无妨pandoc(Haskell,需另行安装)。它对 LaTeX 输入的支持是部分的。
  • TikZ 图形是主角 → 别交给转换器:把每张图单独导出为 SVG,alt 自己写。