1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
*【編集中】 [#ref92ed9]
#contents
 
* 方針 [#d8342a00]
- コードで画像を出力したい。
- 特定用途なら専用言語で良い。
- 汎用用途ならコーディングし易さを考慮した汎用言語が良い。svg のタグ打ちはコーダーに優しくない。
 
* 仕様 [#j59f5d78]
- [[blockdiag>http://blockdiag.com/ja/index.html]]という便利な作図ツールが作られている。
-- http://blockdiag.com/ja/index.html
- Python で実装されているため、プラグイン扱いで拡張する。
- blockdiag、seqdiag、actdiag、nwdiag、packetdiag とコマンド名が分かれているが、コードから判別可能のため、プラグインは diag に統一。
- 出力は HTML と親和性の高い SVG 直埋め込みとする。ただ、IE8など非対応ブラウザには png で出すべし。
 
* 実装 [#gb40f8e7]
- plugin/diag.inc.php を新規作成。
###
<?php
 
function plugin_diag_convert()
{
    $arg = rtrim(join(func_get_args(), ','), ',');   // 末尾の「,」は波引数が空の場合に現れ、不要物。
    return '<div class="diag">'.plugin_diag_core($arg, 'convert').'</div>';
}
 
function plugin_diag_inline()
{
    $arg = rtrim(join(func_get_args(), ','), ',');   // 末尾の「,」は波引数が空の場合に現れ、不要物。
    return '<span class="diag">'.plugin_diag_core($arg, 'inline').'</span>';
}
 
function plugin_diag_core($arg, $mode)
{
    $diag_dir = './diag/';                                      // 数式と数式画像のパス
    $err_msg_end_phrase = 'No pages of output.'.PHP_EOL;    // エラー終了を示す文字列(platexの出力依存)
    
    $prefix_convert = 'diag-nc-';             //  ブロック用ファイル衝突を避けるための接頭語
    $prefix_inline  = 'diag-ni-';             // インライン用ファイル衝突を避けるための接頭語
    
    $key = ($mode=='inline') ? $prefix_inline.md5($arg) : $prefix_convert.md5($arg);
    
    $diag_euc = $key.'.euc.diag';       // 照合用引数出力(保存ファイル)
    $diag_utf = $key.'.utf.diag';       // コンパイル出力(保存ファイル)
    $img = $key.'.svg';                 // 数式の画像出力(保存ファイル)
    
    $old_dir = getcwd();
    chdir($diag_dir);
    
    if (!file_exists($img) || $arg != file_get_contents($diag_euc))
    {
        $std  = $key.'.std.log';   // Tex の標準出力、エラー出力用
        $euc  = $key.'.std.log';   // Tex の標準出力、エラー出力用
        
        flush();    // Timeout 対策
        
        //$arg = "diag {\n" . $arg . "\n}";      // コード補完
        //$arg = mb_convert_encoding($arg, 'utf8-win');
        
        $command = "blockdiag ";
        //$command = str_replace(";", ";\n", $command);
        if (preg_match(   '/^\s*seqdiag\b/', $arg)) {$command =    "seqdiag ";}
        if (preg_match(   '/^\s*actdiag\b/', $arg)) {$command =    "actdiag ";}
        if (preg_match(    '/^\s*nwdiag\b/', $arg)) {$command =     "nwdiag ";}
        if (preg_match(  '/^\s*rackdiag\b/', $arg)) {$command =   "rackdiag ";}
        if (preg_match('/^\s*packetdiag\b/', $arg)) {$command = "packetdiag ";}
        
        //$arg = mb_convert_encoding($arg,  'SJIS-WIN', 'UTF-8');
        //$arg = mb_convert_encoding(mb_convert_encoding($arg, 'sjis-win', 'eucJP-win'), 'UTF-8', 'sjis-win');
        
        file_put_contents($diag_euc, $arg);
        exec('nkf -w '.$diag_euc.' > '.$diag_utf);
        exec($command . $diag_utf.'  -f %windir%\fonts\msgothic.ttc -Tsvg -o '. $img . ' 2> ' . $std );
        exec('nkf -e --overwrite '.$img);
        
        flush();    // Timeout 対策
        if (!file_exists($img)) // Tex Error
        {
            $err_flag = false;
            $err_code = "diag Error:\n\n";
            
            if ($log_code = fopen($std, 'r'))
            {
                while (!feof($log_code)) 
                {
                    $msg = fgets($log_code);
                    $err_code .= $msg;
                }
                fclose($log_code);
            }
            chdir($old_dir);
            return '<pre class=diag_error_title>'.$arg.'</pre><pre class=diag_error_message>'.$err_code.'</pre>';
        }
        flush();    // Timeout 対策
    }
    
    $xml = file($img);
    array_shift($xml);
    array_shift($xml);
    $match = array();
    preg_match('/^<svg[^>]+viewBox\s*=\s*\"\s*\d+\s*\d+\s*(\d+)\s*(\d+)\s*\"/', $xml[0], $matches);
    $width  = $matches[1];
    $height = $matches[2];
    $svg = implode($xml);
    
    $agent = getenv('HTTP_USER_AGENT');
    chdir($old_dir);
//  return '<img style="width:'.$width.'em; height:'.$height.'em; vertical-align:'.$depth.'em;". src="'.$diag_dir.$img.'" alt="$$'.$arg.'$$" title="'.$arg.'">';
//  return '<img src="'.$diag_dir.$img.'" alt="'.htmlspecialchars ($arg).'" title="'.htmlspecialchars ($arg).'">';
//  return '<object type="image/svg+xml" data="'.$diag_dir.$img.'" style="width:'.$width.'; height:'.$height.';" alt="'.htmlspecialchars ($arg).'" title="'.htmlspecialchars ($arg).'"></object>';
//  return $svg.'<pre>'.htmlspecialchars(print_r($matches, TRUE)).'</pre>';
    return '<div style="width: '.$width.'px;" >'.$svg.'</div>';
}
?>
###
 
* 開発メモ [#n362f009]
*** 文字コード変換 [#z22d52cc]
- 日本語を扱うため、EUC ⇒ UTF8 ⇒ EUC と変換する必要がある
-- 流用した PukiWiki が EUC ベースなため、プラグイン引数は EUC
-- diag 達の標準エンコーディングは UTF8なため、コンパイル前に変換する必要がある。
-- PukiWiki で出力される HTML に直埋め込みするため、再度 EUC に変換する必要がある。
- 訳分からんが、PHP の mb 関数は変換してくれない。
-- http://www.asp-edita.jp/doda/one/doda5728_15.html
- とりあえず、nkf というツールがあったので、それで仮実装。
-- Tex にあった。
 
*** svg 非対応ブラウザ [#u0259b28]
- ブラウザ情報を解析して、png で出すべし。
- 技術的に実現可能と分かっているが、検証できそうにないので先延ばし…
-- ブラウザ情報を表示するページでも用意し、他力本願で報告フォームを使おうか?
    初基 一覧 検索 最新 バックアップ リンク元   ヘルプ   最終更新のRSS