はじめに
僕はtexを使ってドキュメントを作ることが少なくないのですが,texでコンパイルした数式や表などを画像として保存したい場面にたまに出くわします (みなさんはそうではないかもしれませんが僕は出くわします).
さて,このようなときに便利なサイトがtexclipです.ここは,ブラウザにtexコードを入力すると画像化してくれる素晴らしいサイトです.
しかしながら,数式が少し間違っていたり(例えば$f_{\mathrm{max}}$を$f_{max}$と間違える),ちょっと表にデータを付け加えたりするとき,再度ブラウザで入力するのがだるくなります.経験上こういうウェブサービスを使うのはちょっとした用途で使うことが多く,どうせもう使わないからと言ってデータを手元に保存しない人がいます (僕).このようなとき,再度ブラウザにデータ入力するのは非常に労力のかかることです.
そこで,どうせならはじめからローカルで書けばいいじゃないかということになります.でも,ローカルで書いたtexファイルの中身をブラウザにコピペするのはやはりめんどくさいので,texclipと同じ機能をもつCLIのアプリがあれば楽になるんじゃなかろうか,ということで作りました.
何を作ったの?
tex2fig
というCLIアプリ (コマンド) を作りました.
ローカルのtexファイルを画像(.svg)に変換します.
簡単に説明するとtexファイルをtexclipに投げてsvgを取ってくるコマンドです.
特徴
- Windows, mac, Linuxに対応しています.(Windowsとmacは動作未確認)
- 実行ファイルで配布しているので,ダウンロードすればすぐに利用できます.
- ウェブ経由で図を作るのでlatex環境がない方でもお使いいただけます.
-
ヘッダレスなtexファイルを画像化できます(
\documentclass{article}
とかが不要).
画像化できるtexファイル例:
\begin{align*}
e^{i\pi} = -1
\end{align*}
\begin{tabular}{c|cc}
& Col. 1 & Col.2 \\ \hline
Row 1 & 1 & 2 \\
Row 2 & a & b \\
\end{tabular}
画像化したいところだけ書いて,コマンドに投げるだけで大丈夫です.
僕,無知なの? → はいそうです
-
tex2fig
完全に同じ名前ですね.この記事を書いているときに知りました.こちらはPythonとlatexで実装されているみたいですね.多分すべてローカルで実行するので,こちらのほうが速いでしょう.
どう使うの?
まず,gitlabからクローンしてください.
使用例
-
svg2fig example.tex
: 単一ファイルの画像化 -
svg2fig -d /dir/ table.tex
: 保存先を指定して画像化 -
svg2fig -w 20 *.tex
: 複数ファイルの画像化
file.tex
を変換すると-d
で指定したディレクトリにfile.svg
が生成されます.
オプション
-
-d
: 保存先の指定 (default ./) -
-w
: Goroutineの並列数 (default 10)
Go コード
全文は,gitlabを参照してください.コードは非常に簡単です.特に大事そうな部分を説明します.
- Goroutine, channelを用いた並列処理
// unpack files with ?Goroutine?
ch := make(chan string)
wg := sync.WaitGroup{}
// make workers
for i:=0; i<*numWorkers; i++{
wg.Add(1)
go tex2Svg(&wg, ch)
}
// channel ni fileName wo nagasu
for _, fileName := range args {
ch <- fileName
}
close(ch)
wg.Wait()
args
にコマンドラインから受け取ったtexファイル名が入っています.この並列処理の書き方は,このサイトを参考にしました.*numWorkers
で並列数(Goではプロセスでもスレッドでもないらしいからなんと呼ぶか不明)を指定している.あと,WaitGroupをつかって全ての処理が終わるのを待っている.
- メインの処理
func tex2Svg (wg *sync.WaitGroup, ch chan string) {
defer wg.Done()
for {
texPath, isOpen := <-ch
if !isOpen{
return
}
texSource := loadTexSource(texPath)
svgSource := fetchSvgSource(texSource)
saveSvg(svgSource, texPath)
}
}
非常にシンプル (だと思う).これもここを参考にしている.正直,Go初心者の僕には何をしているか分からない.特にdefer
は謎.
- texclipからsvgを取ってくるところ
// Global variables
var (
UrlHead = "https://texclip.marutank.net/render.php/_.svg?s="
UrlFoot = "&f=c&r=300&m=s&b=f&k=f"
)
func fetchSvgSource(texSource string) ([]byte) {
var strQuery string
strQuery = url.QueryEscape(texSource)
payload, _ := http.Get(UrlHead+strQuery+UrlFoot)
defer payload.Body.Close()
svgByteSource, _ := ioutil.ReadAll(payload.Body)
return svgByteSource
}
ここを参考に書いた.基本的にtexclipのURLにパーセントエンコーディング (これが何かは不明) したtexのソースを書いてGetすればいい.多分UrlHead
とUrlFoot
の部分を書き換えるともっと機能を追加できる.
ほんとに並列化できてるの?
このほとんどコピペで作者が何も理解していない並列処理であるが,本当にgo
で早くなるのか一応調べた.クローンしたディレクトリ上で以下のコマンドで試せます.test/
には[alphabet].tex
(計26ファイル) が入っています.
$ time ./tex2fig -d test -w 1 test/*.tex
real 0m13.456s
user 0m0.117s
sys 0m0.061s
$ time ./tex2fig -d test -w 2 test/*.tex
real 0m7.415s
user 0m0.133s
sys 0m0.039s
$ time ./tex2fig -d test -w 4 test/*.tex
real 0m6.252s
user 0m0.162s
sys 0m0.021s
$ time ./tex2fig -d test -w 26 test/*.tex
real 0m6.078s
user 0m0.177s
sys 0m0.074s
一応速くなっていますね.ちなみに僕のPCのCPUは2 CoreのCeleron(R) N4000 CPU @ 1.10GHz.まぁ,うん.もっと高性能なCPUなら恩恵あるかも.Web経由だからそこがボトルネックになってるかもしれません.
ファイル数と並列数を同じにして時間を計測(time tex2fig -w n 1.tex ... n.tex
みたいにして実行)すると,ファイル数が1のときは大体$0.7\ \mathrm{[sec]}$かかり,1ファイル増える毎におよそ$0.2\ \mathrm{[sec]}$ずつ増加していきました.つまり,これを等差数列としてみると,26ファイルの処理にかかる時間は
t_{26}=0.7 + (26-1)\times 0.2= 5.9\ \mathrm{[sec]}
となり,実際に大体この通りに動いていることが確認できます.この1ファイルあたりの時間の増加が何によるものかはよくわかりません
おわりに
Golangはio
とかnet
に便利な関数がいろいろあることをしれました.
いいね,コメントいただけると嬉しいです.