はじめに
資料やブログ記事にきれいな数式画像を載せたいとき、LaTeXをそのまま使えない環境では一手間かかる。
MathJax(ブラウザでLaTeXをレンダリングするJSライブラリ)と Puppeteer を組み合わせることで、コマンド一発でLaTeX数式を高解像度のPNGに書き出せるスクリプトを作った。
環境・前提
- macOS
- Node.js インストール済み
- インターネット接続必要(MathJaxをCDNから取得するため)
セットアップ
mkdir mathjax-to-png cd mathjax-to-png npm init -y npm install puppeteer
mkdir mathjax-to-png
cd mathjax-to-png
npm init -y
npm install puppeteer
スクリプト(render_mathjax.js)
const puppeteer = require(‘puppeteer’); const fs = require(‘fs’);
const math = process.argv[2] || ‘\\frac{a}{b}’;
(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage();
await page.setViewport({ width: 4000, height: 600, deviceScaleFactor: 3 // 3倍スケーリング ≈ 300dpi相当 });
await page.setContent(`
// MathJaxの描画完了を待つ await page.waitForFunction(() => { return document.body.getAttribute(‘data-mathjax-ready’) === ‘true’; });
const mathElement = await page.$(‘#math’); await mathElement.screenshot({ path: ‘output.png’ });
await browser.close(); })();
const puppeteer = require('puppeteer');
const fs = require('fs');
const math = process.argv[2] || '\\frac{a}{b}';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({
width: 4000,
height: 600,
deviceScaleFactor: 3 // 3倍スケーリング ≈ 300dpi相当
});
await page.setContent(`
<html>
<head>
<script>
window.MathJax = {
tex: { inlineMath: [['$', '$'], ['\\\\(', '\\\\)']] },
svg: { fontCache: 'global' }
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<style>
body { margin: 0; padding: 40px; }
#math { font-size: 80px; }
</style>
</head>
<body>
<div id="math">\\(${math}\\)</div>
<script>
MathJax.startup.promise.then(() => {
document.body.setAttribute('data-mathjax-ready', 'true');
});
</script>
</body>
</html>
`);
// MathJaxの描画完了を待つ
await page.waitForFunction(() => {
return document.body.getAttribute('data-mathjax-ready') === 'true';
});
const mathElement = await page.$('#math');
await mathElement.screenshot({ path: 'output.png' });
await browser.close();
})();
実行方法
コマンドライン引数にLaTeX形式の数式を渡す。
node render_mathjax.js ‘数式(LaTeX)’
node render_mathjax.js '数式(LaTeX)'
引数を省略すると `\frac{a}{b}` がデフォルトで使われる。
node render_mathjax.js
node render_mathjax.js
実行例
分数
node render_mathjax.js ‘\frac{a}{b}‘
node render_mathjax.js '\frac{a}{b}'
二次方程式の解の公式
node render_mathjax.js ‘x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}‘
node render_mathjax.js 'x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}'
総和(シグマ)
node render_mathjax.js ‘\sum_{i=1}^{n} x_i’
node render_mathjax.js '\sum_{i=1}^{n} x_i'
積分
node render_mathjax.js ‘\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}’
node render_mathjax.js '\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}'
実行すると同じディレクトリに `output.png` が生成される。
ポイントまとめ
- 数式要素だけをトリミング:
page.$(‘#math’) で取得した要素に対して .screenshot() を呼ぶことで、余白なく数式だけを切り出せる - deviceScaleFactor: 3 で実質300dpi相当の高解像度出力になる
- MathJaxの描画完了待ち:
waitForFunction で data-mathjax-ready 属性が付くまで待機することで、レンダリング前にスクリーンショットが走る問題を防いでいる - フォントサイズ調整:
#math { font-size: 80px; } の値を変えると数式の大きさを調整できる
シェルでのエスケープに注意
バックスラッシュ `\` を含むLaTeX文字列はシングルクォート `’` で囲むと安全。
# OK node render_mathjax.js ‘\frac{a}{b}‘
NG(バックスラッシュが消える)
node render_mathjax.js “\frac{a}{b}“
# OK
node render_mathjax.js '\frac{a}{b}'
# NG(バックスラッシュが消える)
node render_mathjax.js "\frac{a}{b}"
ファイル構成
mathjax-to-png/
├── render_mathjax.js # 変換スクリプト
├── output.png # 生成されるPNG
└── package.json