SATySFiでLaTeXiT的なことをする

この記事は [SATySFi Advent Calendar 2019](https://adventar.org/calendars/3929) 20日目の記事です．19日目はhsjoihsさんによる[MathJaxで私が書くぐらいの内容をSATySFi化するツール](https://hsjoihs.hatenablog.com/entry/2019/12/19/081252)でした．21日目はmonaqaさんです．

LaTeXには言わずと知れた数式画像化ツールである[LaTeXiT](https://www.chachatelier.fr/latexit/)があります．
最近SATySFi用にLaTeXiT的なことをするクラスファイルを作ったので共有したいと思います．

## 追記

LaTeXにはstandaloneというパッケージがあってsatysfi-itと概ね同じことをしてくれるらしいです (知らんかった) ただstandaloneという名前のクラスファイルは既にSATySFiの標準ライブラリに存在していてかつLaTeXのstandaloneとは違って自動でページサイズが小さくならないので混乱を避けるためにこのままsatysfi-itという名前を使い続けます．

## LaTeXiTとは

LaTeXの形式で数式を入力すると画像ファイルとして出力してくれる便利なツールです．

<img width="496" alt="スクリーンショット 2019-12-26 22.21.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11779/9fe1eef5-a381-42e9-fdb5-7b3240783ed7.png">

上記の入力をpngとして出力した場合は以下のような結果が得られます．(背景が透明なのでわかりづらいですが数式のサイズにぴったりなサイズのpngファイルです)

<img width="664" alt="スクリーンショット 2019-12-26 23.46.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11779/f6a34937-e252-660c-621b-2d257d618e01.png">

LaTeXiTはMacだとMacTeXをインストールするときにGUIインストーラーのチェックボックスを外すのを忘れると勝手にインストールされてしまうツールとしても有名ですね．単純な数式だけでなく次のように図式も描けたりします．

<img width="527" alt="スクリーンショット 2019-12-26 22.39.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11779/a37a86f7-f524-986a-673f-658a9216f265.png">

昔はKeynoteでスライドを作るのによく使っていました（Beamerの不自由さがあまり好きではなかったので．）最近は目がComputer Modernしか受け付けなくなってしまったので使わなくなってしまいました．

## SATySFi-iT

LaTeXiTのようなことをSATySFiで実現するのはそんなに難しくありません．もちろんpdfしか出力できませんしSATySFiからGUIを作ることはできないのでざっくりLaTeXiTっぽい感じの出力結果になる(入力の数式にぴったりなサイズの出力が得られる)クラスファイルが作れるという意味です．

実際のクラスファイルのコード (satysfi-it.satyh) は以下のような感じです．

```
@require: base/base
@require: base/fn
@require: base/inline
@require: base/block
@require: base/pager
@require: base/context
@require: base/option-ext

let satysfi-it ?:text-width ?:margin math =
  let text-width = text-width |> Option.unwrap-or 440pt in
  let (top, right, bottom, left) = margin |> Option.unwrap-or (3pt, 3pt, 3pt, 3pt) in
  let default-ctx = Context.make text-width in
  let ib = default-ctx |> Inline.of-math math in
  let (w, h) = (Inline.natural-width ib +' left +' right, Inline.natural-height ib +' top +' bottom) in
  Pager.make-document
    (Page.custom w h)
    (Fn.const (| text-height = 0pt; text-origin = (left, top) |))
    (Fn.const (| header-content = Block.nil; header-origin = (0pt, 0pt); footer-content = Block.nil; footer-origin = (0pt, 0pt) |))
    (default-ctx |> Block.of-inline false false (Fn.const ib))
```

[satysfi-base](https://github.com/nyuichi/satysfi-base)の[開発版](https://github.com/nyuichi/satysfi-base/commit/15f8a18046267fea55b9933a57ba65b71ff3154c)がインストールされていることが前提です．使う時は以下のような感じ．

```
@import: satysfi-it

satysfi-it ${1 + 2 = 3}
```

そして組版の結果が以下のようになります．

<img width="664" alt="スクリーンショット 2019-12-26 23.11.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11779/7da76d2f-9574-af67-471e-6702e40efc40.png">

## 簡単な解説

特に解説するほどの長さでもないですが一応簡単に説明します．

`satysfi-it`は`math`型の値を受け取ってそれを`document`型に変換します．変換の際`Inline.natural-width`と`Inline.natural-height`で受け取ったmathの自然なサイズを計算してそれをページサイズとしています．documentを作るには`Pager.make-document`を使うのですが，この際渡すヘッダ・フッタの設定は適当に潰してあります．

上の例では`1 + 2 = 3`というとても簡単な数式にしてありますが当然可換図式も書けます．ただし現在のところSATySFiで可換図式を簡単に書く方法がないのでここでは省きます．

## 今後の展望

SATySFi-iTはもともとsatysfiで回帰テストを書く際にほしいということで作られました（関連issue: [Create LaTeXiT-sh class file #14](https://github.com/nyuichi/satysfi-base/issues/14)）LaTeXiTと使われ方が異なるあたりがとてもsatysfiっぽいです．一方LaTeXiTと同じユースケースでも便利に使えると思います．GUIなどあるとなお良いかもしれません．