2011/02/08

魔法使いの弟子(その4-1)

【ミッション: LaTeX の数式を簡単に画像化したい】

前回のあらすじ: PDF のスナップショットツールを用いて切り抜いた領域から超てきとうに透過画像を生成するプログラムを作った。

ところが、調べていくうちに、

> platex tmp.tex
> dvipng -T tight -bg Transparent tmp.dvi

というコマンドを打てば、dvi ファイルから自動的に透過 PNG 画像が生成されるという衝撃の事実が判明した。

試しに、
\documentclass[a4j]{jsarticle}
\usepackage{amsmath,amsthm,amssymb}
\usepackage{euler}
\pagestyle{empty}
\newcommand \vect[1] {\textrm{\boldmath $#1$}}
\begin{document}
    \begin{align*}
        e^x = \sum_{n=0}^{\infty}\frac{x^n}{n!}
    \end{align*}
\end{document}
という TeX ファイルで実験したところ、いとも簡単に以下のような画像が得られたではないか(なんか日本語が入っているとダメっぽいけれど)。土曜日の努力はなんだったんだ(なんか日本語が入っているとダメっぽいけれど)。

得られた透過画像
※ デフォルトでは文字色が黒く、認識しづらいので、画像の箇所だけ背景色を変更している。

余談だが、

\newcommand \vect[1] {\textrm{\boldmath $#1$}}

で定義されている vect マクロは数式を太字にするためのもので、個人的にすごく重宝している。例えばベクトルの「x」を入力する際には \vect{x} と書けばよい。



とりあえず便利なコマンドも判った事だし、テキストエリアに入力された数式から透過画像を生成するプログラムを適当に作ってみた。

またこんなくだらないものを…。
ここでのポイントとして、Java からネイティブのコマンドを呼び出すには、

Runtime.getRuntime().exec( command );

と書けばよい。ここで変数 command には、実行したいコマンドの文字列が格納されているものとする。

しかし何故かぼくの自宅の環境ではこれがうまくいかなかった。原因は不明だが、TeX ファイルをコンパイルしようとすると IOExceptionthrow されるのだ。

手を変え品を変え試してみたところ、どうやらバッチファイルを call するだけならうまく動いてくれる事が判ったので、先ほどのコマンドをバッチファイルにまとめて、 exec メソッドではそのバッチファイルを呼ぶだけにした。

結局、「げっちゅ」ボタンが押されたときの振る舞いの主なコードはこんな感じになった。「げっちゅ」って……。

private void buttonActionPerformed(java.awt.event.ActionEvent evt) {                                          
    String header = "\\documentclass[a4j]{jsarticle}\n"
            + "\\usepackage{amsmath,amsthm,amssymb}\n"
            + "\\usepackage{epic, eepic}\n"
            + "\\usepackage{euler}\n"
            + "\\pagestyle{empty}\n"
            + "\\newcommand \\vect[1] {\\textrm{\\boldmath $#1$}}\n"
            + "\\begin{document}\n"
            + "\\begin{align*}\n";
    String footer = "\\end{align*}\n"
            + "\\end{document}";

    BufferedWriter bufferedWriter = null;

    File file = null;
    try {
        // テキストエリアから数式のソースを取得
        String eq = textArea.getText();
            
        // 連続する改行文字を消去
        eq = eq.replaceAll("[\n\r][\n\r]+", "");
            
        // texファイルを書き出し
        file = new File("tmp.tex");
        bufferedWriter = new BufferedWriter(new FileWriter(file));
        bufferedWriter.write(header + eq + footer);

    } catch (IOException ex) {
        /* IO例外 */
    } finally {
        try {
            bufferedWriter.close();
        } catch (IOException ex) {
            /* IO例外 */
        }
    }

    // バッチファイルのコール
    try {
        Process proc = Runtime.getRuntime().exec("cmd.exe /c start\ncompile.bat");
        proc.waitFor();
    } catch (IOException ex) {
        /* 例外処理 */
    } catch (InterruptedException ex) {
        /* 例外処理 */
    }
}

この改善策の副作用は、Java のソースに OS 依存のコマンドを埋め込まなくて済む(せいぜいバッチファイルを呼ぶ程度)という事だ。

背景が黒いブログに貼るには階調を反転させる必要がある。前回はわざわざ ARGB の各成分に分解して各々を反転させていたが、この処理は(可読性はさておき)一行で書けてしまう。

color = (0xff << 24 & color) | (0xffffff & ~color);

だいぶすっきりした。

というわけで、 色々アレだが、とりあえずミッションコンプリートである。昨日のドラッグアンドドロップをサポートすれば、より使いやすくなりそうだ。わはー。