LaTeX の数式を PNG と SVG に変換するスクリプト

先日,LaTeX の数式を PNG と SVG に変換する方法についての記事を載せた.この方法を使いやすくスクリプト化してみた.

準備:テンプレート LaTeX ファイルの用意

テンプレート(ひな型)となる LaTeX ファイルを用意する.以下のような構成が基本:

  • KozGoProVI-Medium.otf
  • KozMinProVI-Regular.otf
  • pdffonts.map
  • latex-eq.tex

これらのファイルを適当なフォルダにおく.ここでは ~/bin/linux/templates-eql 以下においてあるものとする. KozGoProVI-Medium.otf, KozMinProVI-Regular.otf は /opt/Adobe/Reader8/Resource/CIDFont/Koz*.otf へのシンボリックリンクで, pdffonts.map は以下のような「フォントマップファイル」だ:

rml    H   KozMinProVI-Regular.otf
rmlv   V   KozMinProVI-Regular.otf
gbm    H   KozGoProVI-Medium.otf
gbmv   V   KozGoProVI-Medium.otf

これら3つは,PDFにフォントを埋め込むために必要だ.詳細は, LaTeX の数式を PNG と SVG に変換する を参照.

最後の latex-eq.tex は,以下のようなテンプレートだ:

\documentclass[11pt,a4j,fleqn,leqno]{jarticle}

\usepackage{latexsym}
\usepackage{array}
\usepackage{calc}
\usepackage{amsmath, amsfonts}
\usepackage{amssymb}
\usepackage{ascmac}  % 枠つき環境

\usepackage[dvips]{graphicx}
\usepackage[dvips]{color}
\usepackage{epsfig,subfigure}
\usepackage{wrapfig}
\usepackage{calligra}
\usepackage{alltt}

% フォント変更
\usepackage{mathpple}
\renewcommand{\rmdefault}{ppl}
\renewcommand{\sfdefault}{phv}
\renewcommand{\ttdefault}{pcr}


\begin{document}
\pagestyle{empty}
\null\vfil
\input{main}
\vfil\null

\end{document}

この中で main.tex を呼び出しており, main.tex に数式のみ書けばよいようになっている.

スクリプト

次に,指定されたファイル(数式が書かれているとする)を main.tex に置き換え,そこから PNGSVG で出力するようにスクリプトを作成する.ちょっと長いが,以下のような感じ:

#! /bin/sh
usage="usage: eqlatex [-all|-svg|-png|-dvi] [latex-file]\n  if [latex-file] is not specified, std-in is used."
templatedir=~/bin/linux/templates-eql # テンプレートがおいてあるディレクトリ
tmpdir=/tmp/eqlatex$$
outfile=eqlatex
pngres=180 # PNG化するときの解像度

outputmode="all"
if [ $# -ge 1 ] && [ "$1" == "-help" ];  then
  echo -e $usage
  exit 0
fi

if [ $# -ge 1 ];  then
  case "$1" in
    "-svg"|"-png"|"-dvi"|"-all")
      outputmode=${1/-/}
      shift;;
  esac
fi

if [ $# -gt 1 ];  then
  echo -e $usage
  exit 1
fi

if [ -d $tmpdir ];then
  rm -rf $tmpdir
fi
mkdir $tmpdir

if [ $# -eq 0 ];  then
  cp /dev/stdin $tmpdir/main.tex
else
  cp $1 $tmpdir/main.tex
  outfile=`basename ${1/.tex/}`
fi

cp -a $templatedir/* $tmpdir

cd $tmpdir


ifile=latex-eq
fontsmap=pdffonts.map

error=1
if platex -halt-on-error ${ifile}.tex; then
  if [ -n "`grep 'newlabel' ${ifile}.aux`" ]; then
    platex -halt-on-error ${ifile}.tex
  fi
  if dvipdfmx -f ${fontsmap} -o ${ifile}.pdf ${ifile}.dvi; then
    error=0
  fi
fi

if (($error));then
  echo 'error in compiling the latex source.'
  echo "logs are saved to $tmpdir/${ifile}.log"
  exit 1
fi

if [ $outputmode == 'all' ] || [ $outputmode == 'svg' ];then
  gs -q -r20480 -sDEVICE=epswrite -sOutputFile=${ifile}.eps -dNOPAUSE -dBATCH -dSAFER -dEPSCrop -dEPSFitPage -dUseCropBox ${ifile}.pdf
  pstoedit -f plot-svg -dt -ssp -sclip ${ifile}.eps | \
    sed 's/<rect[^<>]\+id=\"background\"[^<>]*>//g' > ${outfile}.svg
fi

if [ $outputmode == 'all' ] || [ $outputmode == 'png' ];then
  gs -q -sDEVICE=pngalpha -sOutputFile=${outfile}.png -r${pngres} -dNOPAUSE -dBATCH -dSAFER -dEPSCrop -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 ${ifile}.pdf
  convert -trim +repage ${outfile}.png ${outfile}.png
fi

cd -
case $outputmode in
  "all")
    mv $tmpdir/${outfile}.{png,svg} .
    echo "${outfile}.{svg,png} are generated";;
  "svg"|"png")
    mv $tmpdir/${outfile}.$outputmode .
    echo "${outfile}.$outputmode is generated";;
  "dvi")
      mv $tmpdir/${ifile}.$outputmode ${outfile}.$outputmode
    echo "${outfile}.$outputmode is generated";;
esac
echo "latex logs are saved to $tmpdir/${ifile}.log"

このスクリプト(ここでは eqlatex というファイル名で保存されているとする)は,以下のように使用する:

# (数式ファイル名).png, (数式ファイル名).svg が生成される:
eqlatex (数式ファイル名).tex
eqlatex -all (数式ファイル名).tex
# (数式ファイル名).png が生成される:
eqlatex -png (数式ファイル名).tex
# (数式ファイル名).svg が生成される:
eqlatex -svg (数式ファイル名).tex
# (数式ファイル名).dvi が生成される:
eqlatex -dvi (数式ファイル名).tex
# eqlatex.png, eqlatex.svg が生成される:
(数式を出力するコマンド) | eqlatex -all

例えば,
test.tex:

\def\mvec#1{\mathbf{\boldsymbol{#1}}}
\begin{align}
  \frac{\partial{}y(\mvec{x}_n)}{\partial\mvec{w}}
     = \frac{\partial(\mvec{w}^\top \mvec{\phi}(\mvec{x}_n) + b)}{\partial\mvec{w}}
     &= \mvec{\phi}(\mvec{x}_n) \\
  \frac{\partial{}L}{\partial\mvec{w}}
    = \mvec{w} - \sum_{n=1}^{N}{a_n t_n\mvec{\phi}(\mvec{x}_n)} = 0
    &\qquad\Longrightarrow\quad \mvec{w} = \sum_{n=1}^{N}{a_n t_n\mvec{\phi}(\mvec{x}_n)}  \\
  \frac{\partial{}L}{\partial{}b}
    = - \sum_{n=1}^{N}{ a_n t_n } = 0
    &\qquad\Longrightarrow\quad \sum_{n=1}^{N}{ a_n t_n } = 0  \\
  \frac{\partial{}L}{\partial{}\xi_n}
    = C - a_n - \mu_n = 0
    &\qquad\Longrightarrow\quad a_n = C - \mu_n \quad\text{for~} n=1,2, \dots, {}N
\end{align}

に対して

eqlatex -png test.tex

を適用すると, test.png が生成される.

ほか, PNG 出力時の解像度を指定できるようにしてもいいかもしれない.
テンプレート latex-eq.tex にマクロを書いておくと,使いやすくなると思う.

fixme:

  • ページサイズをぴったりにできない (SVG)
  • 日本語の句読点(,.)が出力されない