#latex #pandoc #svg #markdown #convert-markdown #pdf-file #convert-text

程序 just-latex

一个简单的 Pandoc 过滤器,允许使用实际的 LaTeX 引擎在 Markdown 中渲染 LaTeX 片段

6 个版本

0.2.1 2022 年 10 月 20 日
0.2.0 2022 年 10 月 19 日
0.1.3 2022 年 6 月 21 日

2053命令行工具

MIT 许可证

7.5MB
10K SLoC

C 9K SLoC // 0.2% comments Rust 1.5K SLoC // 0.0% comments

包含 (压缩文件,205KB) dimensions.numbers

just-latex

如何在网页上渲染 LaTeX 片段? MathJaX? KaTeX?为什么不……直接使用 LaTeX 呢?

license shield

Just-latex 是一个简单的 Pandoc 过滤器,它串联了 TeX 生态系统中的多个现有工具,以便在将文档转换为 HTML 时使用实际的 LaTeX 引擎来渲染 LaTeX 片段。它旨在填补市场空白,为受 MathJaX 或 KaTeX 限制的用户提供一种新选择。

特性

  • 完全兼容 TeX/LaTeX,因为我们只是在底层调用它们。这意味着您可以定义宏、更改字体、使用 tikz 等。——就像您在 LaTeX 文档中所做的那样。
  • 使用 Pandoc,因此它支持广泛的输入格式,并且可以相对容易地嵌入到各种工作流程中,例如,如果您使用 Hexo 运行的博客(像我一样),则可以使用 hexo-renderer-pandoc
  • 片段被转换为 SVG 图像,无论缩放如何,看起来都很好。
  • 压缩 SVG,以确保生成的页面不会因体积过大而膨胀。

演示

demo

请参阅 examples/demo.mdexamples/demo.html 以展示此程序。演示功能使用 cmbright 包更改字体,使用 tikz 创建图表,以及使用 algpseudocode 排版伪代码。生成 demo.html 的命令是(在 examples/ 下运行)

pandoc demo.md --filter ../target/debug/just-latex -o demo.html

(假设您有一个调试构建) 演示部分改编自 此处

另一个演示 examples/fwht.md 实际上是多年前我写的 博客文章。它包含更多的数学内容,应该被视为此程序的典型用例。

examples 文件夹中还包括一个示例配置文件。

注意:出于安全原因,GitHub 限制了托管 HTML 文件的预览。如果您想检查 htmls,您可以使用类似 https://htmlpreview.github.io 的服务。 演示页面链接

与 ... 的比较

MathJaX 和 KaTeX

我创建这个程序的目标与MathJaX和KaTeX不同。后者在其舒适区表现良好,但本质上它们仍然是TeX的JS部分移植,因此两者都存在局限性。

例如,作为衬线字体,Computer Modern系列实际上在屏幕上看起来并不好,MathJaX 3和KaTeX也没有提供其他选项(尽管MathJaX对它们使用的CM字体进行了微调)。在LaTeX中,我们可以自由使用诸如cmbrightarevbeamer之类的包,或者使用unicode-math加载OTF数学字体来解决问题,不是很好奇我们能否在Web上做到这一点吗?

另一个例子是宏的使用。MathJaX和KaTeX可以处理宏,但如果你在其中一个块中定义了一个宏并在另一个块中使用它,事情可能会变得有点棘手。

这个项目最初是为像我这样的博客作者设计的,其中大部分内容都是静态创建的,并且可以静态渲染。在实时和动态渲染TeX方程式方面,MathJaX和KaTeX仍然是无敌的。

基本上,如果你对MathJaX和KaTeX感到满意,就使用它们。如果你想探索打破这些库强加的限制,请查看这个!

TeX4ht、LaTeXML、Tralics等。

这些程序将LaTeX文档转换为HTML,而just-latex处理Markdown或Org等格式的LaTeX片段。当然,你可以使用Pandoc将Markdown文档转换为LaTeX,然后调用这些工具将其转换为HTML,但这似乎有点复杂。这些工具也是大型系统,需要一些设置。此外,据我所知,LaTeXML和Tralics是TeX仿真器,因此可能存在兼容性问题。

此外,请注意,这些系统试图通过识别输入文档中的某些元素并以“网络方式”处理它们来变得聪明,例如,数学转换为MathML或传递给MathJaX,文本被提取出来以供浏览器重新排版。这本身似乎可能是一个问题来源。

相比之下,just-latex是小型、简单且愚笨的。它用Rust编写,大约有1000行代码,并使用TeX社区中成熟的库,因此你可以在10分钟内完全理解其工作原理(你将在下面看到),并且有99%的把握渲染结果将与你在PDF中看到的结果相同。

SwiftLaTeX

SwiftLaTeX是将整个TeX引擎编译成WebAssembly并在浏览器中运行的。它实际上不应该与这个程序比较,因为前者在客户端浏览器中运行,而后者在服务器端进行所有渲染。

工作原理

  1. Just-latex是Pandoc过滤器,因此Pandoc将处理输入文档的解析——无论是Markdown、RestructuredText、Org还是Pandoc支持的其他任何内容。
  2. 程序识别Pandoc提供的文档树中的MathInline元素。
  3. 然后按照它们出现的顺序(进行一些去重)将这些片段连接起来,用用户定义的前置和后置文包围结果,并将结果写入临时目录中的.tex文件。例如,前置文可能是
    \documentclass[12pt]{article}
    \usepackage{amsmath, amssymb, amsthm, bm}
    \begin{document}
    
    后置文
    \end{document}
    
  4. 它调用(La)TeX(可以是pdfTeX、XeTeX或LuaTeX)将那个.tex编译成PDF文件。
  5. 然后调用dvisvgm将PDF转换为SVG。Dvisvgm包含在现代TeX发行版中。
  6. 对于每个片段,程序使用 SyncTeX 库来计算它在 PDF 和 SVG 中的位置。SyncTeX 已经集成在现代 TeX 引擎中多年,并且是几乎所有 TeX 编辑器用来实现源代码与输出同步的库。
  7. 通过查看实际路径,使用 usvg 库对区域进行细化。
  8. MathInline 节点被替换为带有正确样式的 RawInline 节点和 <img>,以显示 SVG 的计算区域。例如:
    <img src="...#svgView(viewBox(0.42,-15567.08,23.07,11.62))"
         class="svg-math" style="width:23.07pt;height:11.62pt; 
         top:2.66pt;position:relative;">
    
    对于内联片段,将注意将图像的基线与周围文本的基线对齐。
  9. SVG 本身是 LZMA 压缩的,然后使用 base64 编码,然后嵌入到一个短的 JavaScript 代码中,该代码在页面加载时解压缩 SVG,生成对象 URL 并填充上述 ... 部分在 <img> 标签中。此代码,以及加载 LZMA 解压缩器(大小为 7 KB)的 <script> 代码,作为 RawBlock 节点附加到文档树中。
  10. 程序将修改后的树返回给 Pandoc,Pandoc 完成工作并输出单个 HTML 文件。当页面加载时,您将看到渲染的片段与在 PDF 中显示的完全一样。

就是这样。10 步,1 个输入文件,1 个输出文件。

依赖关系和构建

要运行此程序,您将需要 Pandoc 和一个 TeX 发行版。要构建它,您还需要 Rust 工具链和 C 工具链。克隆此存储库(确保使用 git clone --recurse-submodules 以克隆 synctex 代码),然后运行 cargo build

配置

Pandoc 过滤器不能直接从命令行获取参数,所以 just-latex 从不同位置的文件读取配置。

  • 它首先会在可执行文件相同的目录下寻找 jlconfig.toml(当涉及符号链接时可能会 产生歧义),并将其作为配置文件加载。
  • 然后,它会在工作目录下寻找 jlconfig.toml,如果存在则加载它。

配置文件不需要指定所有配置项,因为它只是覆盖先前加载的配置项。

从 0.1.3 版本开始,您还可以在文档的 Front Matter YAML 中按文档配置 just-latex。例如:

---
jlconfig:
  latex: lualatex
---

这告诉 just-latex 使用 LuaLaTeX。或者,您也可以将 jlconfig.latex: lualatex 作为缩写。由于 Pandoc 处理元数据块的方式,just-latex 当前实现的文件内配置可能会出现错误。错误报告总是受欢迎的!

所有配置项都在 config.rs 中定义,并具有默认值。

模式

Just-latex 可以在 PDF 或 DVI/XDV 模式下运行,PDF 模式是默认模式。速度相似。这些模式的不同之处在于使用的中间格式。

在PDF模式下,just-latex指示LaTeX引擎生成PDF文件,dvisvgm将PDF文件转换为SVG。一切运行良好,除了dvisvgm将所有文本转换为SVG路径,使用PDF输入。因此,SVG文件变得庞大,文本不可选择。just-latex的内部优化器专门针对这个痛点设计,当SVG文件未压缩时可以大大减轻这个问题,但在它们压缩之后效果并不明显。

在DVI/XDV模式下,dvisvgm可以保留文本并高效地嵌入子集化的字体,生成更精简的SVG文件和更快的加载时间。(不幸的是,由于使用了片段标识符,文本仍然不可选择。这个问题正在解决。)此外,浏览器将以与body文本相同的文本渲染堆栈渲染片段中的文本,因此希望渲染将更加一致和快速。然而,需要注意的是,DVI和XDV几乎已经废弃的格式,因此某些包(尤其在某些场景下的TikZ)可能需要特殊的配置才能正确使用。由于usvg的工作方式,just-latex的内部SVG优化器与DVI/XDV模式不兼容,因此必须禁用。

要切换模式,请在您的配置文件中设置mode = "pdf"mode = "dvi"mode = "xdv"。DVI模式仅适用于pdfLaTeX,XDV模式仅适用于XeLaTeX,因此请确保模式与您选择的引擎匹配。由于dvilualatex在大多数情况下不是很有用,因此just-latex不支持LuaLaTeX的类似模式。如果必须使用LuaLaTeX,请使用PDF模式。(通常,LuaLaTeX不是一个好的选择,因为它本质上较慢,当转换大量文档时尤其令人烦恼。)

技巧

$$中的所有内容都被Pandoc视为数学,而just-latex通常会将其用[]括起来。要写出不被括在数学环境中的LaTeX,您可以

  • $$的开始处使用%raw。程序将检测到这一点。或者,
  • 使用Pandoc的扩展原始属性语法
    ```{=tex}
    % Your code here.
    ```
    
    您不需要在这里键入%raw

请注意,如果您在$$块中写入复杂非数学内容(更新:这似乎是带有空行的块),那么有时Pandoc会尝试聪明地识别您的代码为原始TeX块,但周围的$$将变成普通可见文本。因此,如果您确实要写入非数学内容,建议使用第二种格式(它还不会让试图用MathJaX渲染您的Markdown的编辑器感到不安,例如Typora)。

或者,有时您可能想要一个仅用于宏定义或更改内部TeX变量的块。这是一个问题,因为当just-latex询问SyncTeX这些代码在PDF中的位置时,它会变得困惑——这样的代码本身不产生任何内容!SyncTeX沮丧地返回下一个片段的边界框,这是错误的。在这种情况下,您必须以%dontshow开始这样的块,无论是$$块还是{=tex}块。这会通知just-latex仅将其包含在中间TeX文件中,而不要调用SyncTeX。您可以在示例文件中看到这一点。

请注意,您不能再使用 \TeX\LaTeX。这不是错误,因为在实际的 LaTeX 中这两个命令在数学模式下是无法使用的 -- MathJaX 让我们误以为可以! 您应该使用 \text{\TeX},或者类似的东西。

\let\oTeX=\TeX
\def\TeX{\text{\oTeX}}

同样,您不能在数学模式下使用如 align 这样的环境(您必须使用 aligned)。

从 0.1.2 版本开始支持多页中间 PDF。但仍然建议将所有内容都放在一页上,因为跨页的 SyncTeX 可能会产生意外的结果(由于 TeX 的页面分页器工作方式)。Just-latex 现在采用一些启发式方法来处理这个问题。无论如何,请确保页面没有被页码/页眉/页脚装饰 -- 您可以通过在您的序言中添加 \pagestyle{empty} 来实现这一点(我的意思是,为什么一开始要添加页码呢?没有人会阅读中间 PDF)。此外,内联 LaTeX 片段不能跨页。多页意味着生成多个 SVG,这使得压缩效率降低,生成的 HTML 文件更大(尽管通过 web workers 可以并行解压缩)。您可以使用 \usepackage[paperheight=16000pt]{geometry} 来创建一个足够长的页面,以满足大多数情况。

限制

  • 由于多种原因,渲染片段中的文本不可选择或复制。 这个问题正在解决中。

  • 生成的 SVG 文件可能非常大,尽管这个程序为典型的 Markdown 文档(如博客文章)添加的压缩量不到 100 KB。 这个问题正在解决中。

  • TeX 很慢,dvisvgm 也是。尽管程序本身运行相当快,但转换一个文档仍然需要大约 1 秒。

  • 您负责设置序言,使 LaTeX 片段的字体大小与 HTML 中周围文本的大小相匹配。例如,HTML 的默认文本大小为 12pt,因此您应该将 [12pt] 作为选项传递给 \documentclass{article}。同样,您应该配置页眉模板,使其与您的页眉大小相匹配。

贡献

请随时在问题部分报告任何错误或改进建议。PR 也非常受欢迎。

这有用吗?

是的。

依赖关系

~12–25MB
~392K SLoC