読者です 読者をやめる 読者になる 読者になる

Acetaminophen’s diary

化学に関すること,TeXに関すること,ゆきだるまに関すること。

化学構造式をTeXで(2):自動化の注意点と解消法

追記:新しい記事を書いたので、以下の内容は少々古い。最新はこちら:

ただし、ソフトウェアの概要やインストール方法などは以下の内容を参照。

前回の続きで、残しておいた「自動実行の注意点」について。

 

注意点1:ディレクトリ名

ディレクトリに全角文字が入っていると、たぶん InkscapeSVG ファイルの読み込みに失敗する。したがって PDF 変換が行われず、platex から PDF ファイルが存在しないとエラーが返ってくるはずである。ユーザ名に全角文字が入っていればおそらく致命的で、この場合は手動で Inkscape を開けばたぶん PDF に保存しなおせるはず。

 

注意点2:自動実行プログラムの指定

前回も書いたが、-shell-escape ではセキュリティ上の問題が生じうる。例えば

など参照。もしかすると texmf.cnf を書き換えれば実行許可するプログラムを個別に設定できるかもしれないが未確認で、簡単な回避法を1つ。

 

前提の復習

その前に、基本的な前提知識を確認しておく。とりあえず TeX Wiki の記述を転載する*1

W32TeX や 美文書第6版 からインストールした場合は texmf.cnf の shell_escape_commands に extractbb が指定されていて,

\usepackage[dvipdfmx]{graphicx}

のようにすると,自動的に extractbb が実行されるので,あらかじめ extractbb を実行する必要はありません。

TeX Live 2014, MacTeX-2014 では extractbb の実行は自動化されていません。

自動化したい場合は

Windows の場合は C:\texlive\texmf-local\web2c\texmf.cnf
OS X, Linux の場合は /usr/local/texlive/texmf-local/web2c/texmf.cnf

を作成し

shell_escape_commands = \
bibtex,bibtex8,bibtexu,upbibtex,biber,\
kpsewhich,\
makeindex,mendex,texindy,xindy,\
mpost,upmpost,\
repstopdf,epspdf,extractbb

を書き足して管理者権限で

mktexlsr

を実行します。

platex や pdflatex 実行時に -shell-escape オプションを付けると、時にユーザが意図しないプログラムさえも自動実行されてしまう。これを回避するために、通常は -shell-escape オプションではなく texmf.cnf に shell_escape_commands = として実行を許可するプログラムだけを記述することが推奨されている。この shell_escape_commands を定義した texmf.cnf は通常

  • TeX Live の場合:
    Windows なら C:\texlive\texmf-local\web2c\texmf.cnf
    OS X, Linux なら /usr/local/texlive/texmf-local/web2c/texmf.cnf
  • W32TeX の場合:
    C:\w32tex\share\texmf-dist\web2c\texmf.cnf

に存在するはずであり、それぞれ

shell_escape_commands = \

で始まる数行にわたってコマンド名が列挙されている。これを見る限り、今回実行しようとしている外部プログラムである obabel や inkscape、それに rm は許可されていないわけで、これこそが先ほどまでの説明で -shell-escape オプションをつけるよう説明した理由である。

 

では、どう回避するか

以上を読んで「では、texmf.cnf にプログラム名を追記すればよいのではないか」と思うかもしれないが、それで済めば話は簡単である。しかし obabel や inkscape は完全に TeX とは無関係なので追加の仕方が僕には分からなかった。しかも rm はファイルをゴミ箱を介さず削除するプログラムなので、自動実行に加えるのは危険である。

そこで、\smiles や \obabel というコマンドを含んだ TeX ソースが存在するときに(前回の smiles.tex や obabel.tex でもよい)

  1. SMILES表記を構造式に変換したい部分だけ、つまり本文の \smiles または \obabel コマンドおよびプリアンブルでの定義だけを残し、他を排除した TeX ソースを本文とは別に用意し、これを ChemFigFile.tex と名付ける
  2. いったん ChemFigFile.tex に対して -shell-escape オプションを付けた platex を実行する
  3. 生成したPDFファイルを元々の TeX ソースと同じディレクトリに置き、単に platex を通す(-shell-escape オプションなし)
  4. 通常通り dvipdfmx を通す

という手順を提案する。こうすれば、実質的には texmf.cnf で指定したプログラム以外で自動実行されるのが、安全な \smiles コマンドや \obabel コマンド実行に必要な obabel や inkscape(場合によっては rm も)だけとなる。トリックは、そもそも texmf.cnf で自動実行を許可されているプログラムの中に obabel, inkscape, rm のいずれも含まれていないために、3.で -shell-escape オプションなしの実行を行うと、ここが完全に無視されて変換処理がなにも行われないことにある。それにもかかわらず \includegraphics が強要されているため、結果としてはその3.より前の段階、すなわち2.で生成した PDF が“仕方なく”読み込まれるという感じで説明がつく。

この方法の副次的なメリットとして、外部プログラムを呼び出すプロセスは中間の platex -shell-escape ChemFigFile.tex だけであるので、必要以上に obabel や inkscape を呼び出すことがなくなり、処理が高速化する。しかも、いったん生成した PDF を見て不満があれば、その都度 PDF を直接 InkscapeGUI 操作により編集することができ、それを勝手に上書きされる心配もない*2

 

これでもまだ面倒なので…

ついでに、この1.の手順は面倒なので、自動抽出コマンドを用意した。元となる TeX ソースを autoextract-smiles.tex と呼ぶことにする。プリアンブルの末尾に以下の抽出コマンドを書き加える*3

%%%%% For the purpose of extracting codes of all SMILES figures %%%%%
%%%%% Reference: http://oku.edu.mie-u.ac.jp/tex/mod/forum/discuss.php?d=1411
% Necessary: definition of the intermediate output file
\newwrite\ChemFigFile
 \immediate\openout\ChemFigFile=ChemFigFile.tex\relax
 \immediate\write\ChemFigFile{\string\documentclass{jsarticle}}
 \immediate\write\ChemFigFile{\string\usepackage[dvipdfmx]{graphicx}}
% Options
%% for \obabel (Delete the next line if you don't intend to use `graphvizObabel.sty'; necessary if you don't have `graphvizObabel.sty')
 \immediate\write\ChemFigFile{\string\usepackage{graphvizObabel}}
%% for \smiles (Delete following 9 lines if you don't intend to use \smiles ; if you wish)
 \immediate\write\ChemFigFile{\string\newcounter{smilescounter}}
 \immediate\write\ChemFigFile{\string\setcounter{smilescounter}{1}}
 \immediate\write\ChemFigFile{%
  \string\newcommand{\string\smiles}[1]{%
   \string\immediate\string\write18{obabel -:"\string#1" -O smilesimg\string\arabic{smilescounter}.svg && inkscape -f smilesimg\string\arabic{smilescounter}.svg --export-pdf=smilesimg\string\arabic{smilescounter}.pdf || rm -f smilesimg\string\arabic{smilescounter}.pdf}
   \string\includegraphics{smilesimg\string\arabic{smilescounter}.pdf}
   \string\addtocounter{smilescounter}{1}%
  }%
 }
% Necessary: read and write
 \immediate\write\ChemFigFile{\string\begin{document}}
 \AtEndDocument{%
  \immediate\write\ChemFigFile{\string\end{document}}%
  \immediate\closeout\ChemFigFile%
 }
%% for \smiles
 \let\oldsmiles=\smiles
 \def\smiles#1{%
  \immediate\write\ChemFigFile{%
   \string\smiles{#1}%
   \string\newpage}%
  \oldsmiles{#1}}
%% for \obabel
 \let\oldobabel=\obabel
 \def\obabel[#1]#2{%
  \immediate\write\ChemFigFile{%
   \string\obabel[#1]{#2}%
   \string\newpage}%
  \oldobabel[#1]{#2}}
%%%%%%%%%%

抽出コマンドを書き加えて保存したら、いったん -shell-escape オプションなしで

platex autoextract-smiles.tex

を通す(TeXworks や TeXShop などを用いてもよい)。すると当然であるが obabel や inkscape が実行されないので、PDF ファイルがないというエラーが大量発生する。しかし、根気よく [Enter] しつづけると最終的には ChemFigFile.tex というファイルが同じディレクトリに生成する。これこそが \smiles や \obabel コマンドのみを自動抽出した TeX ソースであり、まさに上の1.にあたる部分を自動化したわけである。

あとは2.から4.に従うだけである。すなわち全体として

  1. platex autoextract-smiles.tex を実行(-shell-escape オプションなし)
  2. platex -shell-escape ChemFigFile.tex を実行
  3. platex autoextract-smiles.tex(-shell-escape オプションなし)
  4. dvipdfmx autoextract-smiles.dvi を実行

今回のソースも一応おいておく(Google):
「autoextract-smiles.tex」「autoextract-smiles.pdf」「ChemFigFile.tex

 

次回は、この方法に関連していくつかの補足を行う。

*1:2014年11月3日9:20現在;一部改変。将来的には TeX Live 2015 以降 extractbb の実行の自動化が模索されているため、この記述が TeX Wiki から削除されてしまう潜在的な可能性がないわけではないため。

*2:補足:生成する PDF ファイルはテキスト情報を保持しているが、中身が少し変である(これは前回紹介した方法でも同じ)。というのも、IllustratorInkscape で構造式の PDF 画像を開いてみるとわかるとおり、PDF ファイルのテキスト部分は二重になっていて、「実際のテキスト」が「アウトライン化で生成したパス」で覆われたかたちである。したがって、編集の際にはこのパス部分をグループ解除で除去し、テキストだけを残すようにするとよいだろう。これに関連した点は次回説明する。

*3:このマクロは TeX Forum の質問への解答で示された例を参考に改変したものである。