数式プラグイン eq の追加 EditToHeaderToFooter

方針 EditToHeaderToFooter

  • 基本仕様はwikihouse.commath2.inc.phpに従う。
    • ただし、ハッシュの衝突が心配のため、数式の同定は生のTeXコードで比較。
    • プラグインの同時呼出しで作業ファイルが衝突するため、全てハッシュ名を用いる。
    • LaTeX、dvipngにより数式画像生成後に、Imagemagicのconvertで画像処理を施す。
  • 数式の解像度、位置決めは、それなりに拘る。
    • 少なくとも IE7、IE8、Firefox3 の100%を満足し、Firefox3 の最大ズームに耐えうること。

仕様 EditToHeaderToFooter

  • パスを通した platex、dvipng と convert を要求。
  • 引数をそのままLaTeXに渡し、最終的にpng画像に変換して出力。
    • ブロックプラグインの場合は、align環境(\begin(align) 〜 \end(align))に渡される。
    • インラインプラグインの場合は、ディスプレイ数式モードに変更されるテキスト数式モード($ \displaystyle 〜 $)に渡される。
  • 作業ファイルと出力ファイルの名前には、数式に基づくハッシュキーを使用。
    • eq/{ハッシュキー}.eq に生のTeX式を保存し、数式の同定に使用。ハッシュキーを同定には使わない。
    • eq/{ハッシュキー}.png に数式画像を出力。
  • ブラウザのズーム対策として、画像を高解像度で出力し、IMGタグのwidthheightで縮小表示。
  • インライン数式の垂直揃えは中心揃え(vertical-align: middle;)。分数線が画像中心に来るようにTeX側で調節する。
    • dviには位置決めのために数式に枠を付けて出力。convertにより枠を除去。
  • 数式がコンパイルでき無い場合、代わりに TeX のエラーを出力。

改造 EditToHeaderToFooter

  • plugin/eq.inc.php を作成して、
       #code(php){{{{
       <?php
       
       function plugin_eq_convert()
       {
           $arg  = rtrim(join(func_get_args(), ','), ',');   // 末尾の「,」は波引数が空の場合に現れ、不要物。
           return '<div class="eq">'.plugin_eq_core($arg, 'convert').'</div>';
       }
       
       function plugin_eq_inline()
       {
           $arg  = rtrim(join(func_get_args(), ','), ',');   // 末尾の「,」は波引数が空の場合に現れ、不要物。
           return '<span class="eq">'.plugin_eq_core($arg, 'inline').'</span>';
       }
       
       function plugin_eq_core($arg, $mode)
       {
           $eq_dir = './eq/';                                      // 数式と数式画像のパス
           $err_msg_end_phrase = 'No pages of output.'.PHP_EOL;    // エラー終了を示す文字列(platexの出力依存)
           
           $prefix_convert = 'eq-nc-';             //  ブロック用ファイル衝突を避けるための接頭語
           $prefix_inline  = 'eq-ni-';             // インライン用ファイル衝突を避けるための接頭語
           $tex_frame_convert  = 'convert.tex';    //  ブロック用フレームファイル名
           $tex_frame_inline   = 'inline.tex' ;    // インライン用フレームファイル名
           $eq_replace_phrase  = '\input{eq}' ;    // フレームファイルで数式を埋め込む部を示す文字列
           
           $key = ($mode=='inline') ? $prefix_inline.md5($arg) : $prefix_convert.md5($arg);
           
           $eq  = $key.'.eq';      // 照合用引数出力(保存ファイル)
           $img = $key.'.png';     // 数式の画像出力(保存ファイル)
           
           $old_dir = getcwd();
           chdir($eq_dir);
           
           if (!file_exists($img) || $arg != file_get_contents($eq))
           {
               // 一時ファイル
               $tex  = $key.'.tex';
               $std  = $key.'.std.log';   // Tex の標準出力、エラー出力用
               $dvi  = $key.'.dvi';
               $aux  = $key.'.aux';
               $log  = $key.'.log';
               $box  = $key.'.box.png';
               $face = $key.'.face.png';
               $edge = $key.'.edge.png';
               $bold = $key.'.bold.png';
               
               flush();    // Timeout 対策
               $tex_code  = file_get_contents(($mode=='inline') ? $tex_frame_inline : $tex_frame_convert);
               $tex_code  = str_replace($eq_replace_phrase, $arg, $tex_code);
               
               file_put_contents($eq  ,$arg     );
               file_put_contents($tex ,$tex_code);
               exec('platex -halt-on-error '.$tex.' > '.$std);
               
               flush();    // Timeout 対策
               if (!file_exists($dvi)) // Tex Error
               {
                   $err_flag = false;
                   $err_code = "Tex Error:\n\n";
                   
                   if ($log_code = fopen($std, 'r'))
                   {
                       while (!feof($log_code)) 
                       {
                           $tex_msg = fgets($log_code);
                           
                                if ($tex_msg[0] == '!'                ) {$err_flag = true ;}
                           else if ($tex_msg    == $err_msg_end_phrase) {$err_flag = false;}
                           
                           if ($err_flag) {$err_code .= $tex_msg;}
                       }
                       fclose($log_code);
                   }
                   chdir($old_dir);
                   return '<pre class=eq_error_title>'.$arg.'</pre><pre class=eq_error_message>'.$err_code.'</pre>';
               }
               exec('dvipng -D 720 -T tight --gamma 2.5 -o '.$box.' '.$dvi);
               if ($mode=='inline') {
                           list($width, $height) = getimagesize($box);
                           exec('convert '.$box.' -crop '.($width-16).'x'.($height-16).'+8+8 -bordercolor #FFFFFF               -threshold 50% '.$face);
               } else {
                           exec('convert '.$box.'                                            -bordercolor #FFFFFF -border 16x16 -threshold 50% '.$face);
               }
               exec('convert '.$face.' -edge 1 -negate '.$edge);
               exec('composite -compose multiply '.$face.' '.$edge.' '.$bold);
               exec('convert '.$bold.' -black-threshold 90% -antialias -blur 1 - | convert - -transparent #FFFFFF -antialias '.$img);
               
               flush();    // Timeout 対策
               unlink($tex );
               unlink($std );
               unlink($dvi );
               unlink($aux );
               unlink($log );
               unlink($box );
               unlink($face);
               unlink($edge);
               unlink($bold);
           }
           list($width, $height) = getimagesize($img);
           
           chdir($old_dir);
           return '<img widht='.round($width/7).' height='.round($height/7).' src="'.$eq_dir.$img.'" alt="eq: '.$arg.'" title="'.$arg.'">';
       }
       ?>
       }}}}
    • 17行目は数式のパスを指定。数式のキャッシュとみなせるため、cache/と同じレベルにeq/を作った。
    • 26行目は数式のハッシュキー。プラグインの種別と数式のmd5ハッシュに依存。
    • 34〜98行目は変換処理。数式が変換済みの場合は分岐が成立せず、処理が省かれる。
    • 47行目、55行目と88行目の flash(); はタイムアウト対策。これらが無いと、大量の数式を変換するとPHPが落ちる。
    • 48、49行目はTeXコードの雛形の読み込みと数式の組み込み(=置換)。52行目で数式のTeXファイルを出力。
    • 56〜76行目はTeXがエラーのときの処理。エラーの場合、ログを解析し、エラーの部分をだけ出力。
      • 67行目と68行目はそれぞれエラー部の開始と終了の検出。これが環境依存のため、変更が必要かもしれない。
    • 77〜86行目は画像処理。インラインプラグインでは位置決め枠の除去のため、ブロックプラグインより処理が多い。
    • 99行目、102行目は数式画像のサイズを取得し、表示すべきサイズを算出し、出力している。
      • 数式画像の表示サイズは、77行目のdvipngの解像度 -D 720 と102行目の $width/7$height/7 の分母で調節可能。
  • eq/convert.tex を作成して、
       #code(tex){{{{
       \documentclass[12pt]{jarticle}
       \usepackage{amsmath,amssymb,bm}
       \usepackage{pukiwiki}
       \pagestyle{empty}
       
       \begin{document}
       \thispagestyle{empty}
       \begin{align*}
       \input{eq}
       \end{align*}
       \end{document}
       }}}}
    • \input{eq} をプラグインに渡されるTeXコードで置換して使用。
  • eq/inline.tex を作成して、
       #code(tex){{{{
       \documentclass[12pt]{jarticle}
       \usepackage{amsmath,amssymb,bm}
       \usepackage{pukiwiki}
       \pagestyle{empty}
   \makeatletter
   \newcommand\eqframe[1]%
   {%
       \setbox0=\hbox{M}%              M   M字
       \setbox1=\hbox{#1}%             X   対象
       \dimen0=\ht1
       \dimen1=\dp1    \advance \dimen1 by  \ht0
       \dimen2=\ht1    \advance \dimen2 by -\ht0
       \dimen3=\dp1
       \advance \dimen2 by 5pt%       手動補正
       \advance \dimen3 by 4pt%       手動補正
       \fbox{%
           \rule{0pt}{\dimen0}%
           \rule{0pt}{\dimen1}%
           {#1}%
           \rule[-\dimen2]{0pt}{\dimen2}%
           \rule[-\dimen3]{0pt}{\dimen3}%
       }%
   }%
   \makeatother
   \begin{document}
   \thispagestyle{empty}
   \eqframe{$ \displaystyle \mathstrut {
   \input{eq}
   } $}
   \end{document}
   }}}}
  • \input{eq} をプラグインに渡されるTeXコードで置換して使用。
fileTexEqMiddleAlign.png 485件 [詳細]
    初基 一覧 検索 最新 バックアップ リンク元   ヘルプ   最終更新のRSS