ソフトウェア/pukiwiki/tchart.inc.php のバックアップ差分(No.3)
更新- 追加された行はこの色です。
- 削除された行はこの色です。
[[公開メモ]] #contents * pukiwiki でタイミング図を書きたい [#q244f333] デジタル信号処理の記事を書くのに、 &tchart( clock _~_~_~_~_~_~_~_~_~_~_ data =====X=DATA========X===== valid _____~~~~~~~~~~______ ready _____________~~______ ready _____________[~~]______ ); こういったタイミング図を書きたくて、 プラグインにしてみました。 * tchart [#c7bb7415] 非常に便利なツールを熊谷正朗さんが公開しておられます。 - タイミングチャート清書ツール tchart~ http://www.mech.tohoku-gakuin.ac.jp/rde/contents/library/tchart/indexframe.html このツールを使うと、 clock _~_~_~_~_~_~_~_~_~_~_ data =====X=DATA========X===== valid _____~~~~~~~~~~______ ready _____________~~______ ready _____________[~~]______ こんな風にテキストで書いたタイミング図を、 &tchart( clock _~_~_~_~_~_~_~_~_~_~_ data =====X=DATA========X===== valid _____~~~~~~~~~~______ ready _____________~~______ ready _____________[~~]______ ); このように画像化できます。 ツール自体の出力はポストスクリプトになるのですが、 このツールの出力はポストスクリプトになるため、 そのままだとホームページ上に表示できません。 本当なら tchart 自体を svg を出力する形に手直しをすれば良いのですが、 ここでは手抜きをして、ポストスクリプトファイルを svg に変換するコードを別途書きました。 * svg ファイルを作るまでの処理 [#l0035e32] そこで、svg を出力する tchart のようなものを作成しました。 gohstscript と pdf2svg がインストールされていれば、 以下のようにしてポストスクリプトから SVG を作成できます。 こちらで紹介しています。[[ソフトウェア/tchart.rb]] LANG:console $ tchart chart.tc chart.eps $ ps2pdf chart.eps chart.pdf $ pdf2svg chart.pdf chart.svg * 処理の流れ [#i7a809f2] + pukiwiki.php を変更して tchart プラグインに複数行にわたる引数を与えられるようにする + tchart を呼び出して eps を作成 + ps2pdf で pdf に変換 https://packages.debian.org/cgi-bin/search_contents.pl?word=ps2pdf + pdf2svg で svg に変換 https://packages.debian.org/search?keywords=pdf2svg + ruby で書いたプログラムで svg の余白をトリミングする + html に直接埋め込んで表示する + 変換結果の svg は次回の表示のためにキャッシュする * tchart ソースから svg を作り、余白をトリミングするスクリプト [#s5d23c0e] ruby で書きました。tchart ソースを与えると標準出力に SVG コードを出力します。 /usr/local/bin/tchart-svg.rb LANG:ruby(linenumber) #!/usr/bin/ruby require "digest/md5" require "tempfile" source = readlines.join('') ##################################################### SVG を作る file = '' temp = Tempfile.open(['tchart', '.tc']) file = temp.path.sub(/\..+/, '') temp.write source+"\n" temp.close system("/usr/local/bin/tchart.pl #{file}.tc #{file}.eps") or exit system("/usr/bin/ps2pdf #{file}.eps #{file}.pdf") or exit system("/usr/bin/pdf2svg #{file}.pdf #{file}.svg") or exit lines = '' open("#{file}.svg") do |svg| lines = svg.readlines end system("/bin/rm #{file}.tc #{file}.eps #{file}.pdf #{file}.svg") ##################################################### トリミングする surface = lines.find_index {|line| line =~ /<g id="surface1"/ } exit -1 unless surface exit -1 unless lines[1] =~ /viewBox="0 0 (\d+) (\d+)"/ viewx = $1.to_f viewy = $2.to_f exit -1 unless lines[surface+1] =~ /d="M (\d+) (\d+) L (\d+) (\d+) L (\d+) (\d+) / offsetx = 0.1 * $1.to_f offsety = 0.1 * $2.to_f boundx = 0.1 * $5.to_f - offsetx boundy = - 0.1 * $6.to_f + offsety lines.delete_at(surface+1) lines[surface] = "<g id=\"surface1\" transform=\"matrix(1,0,0,1,#{-offsetx},#{offsety-viewy})\">\n" lines[1].sub!(/(?<=width=")\d+(?=pt")/, boundx.to_s) lines[1].sub!(/(?<=height=")\d+(?=pt")/, boundy.to_s) lines[1].sub!(/(?<=viewBox\="0 0 )\d+ \d+(?=")/, "#{boundx} #{boundy}") ##################################################### グリフ名を変える svg = lines.join('') key = Digest::MD5.hexdigest(svg)[0,6] ##################################################### 出力する print svg.gsub(/\bglyph/, key) ~ 処理内容は以下のようになっています: - 標準入力へ渡された tchart のソースコードをテンポラリファイルに書き出し、 外部ツールを使って svg に変換する - 作成された svg には A4 いっぱいの余白が付いてしまうので、 四角で囲まれた範囲外の余白を取り除く - 1つの HTML に複数の SVG を貼るとき、グリフ名が重複すると結果がおかしくなってしまうため、 SVG 中のグリフ名を他と重ならないように付け替えます * pukiwiki.php の変更 [#a8322c5d] 標準ではプラグインに渡す引数に改行文字を入れられないので、 tchart プラグインに限って改行入りの引数を渡せるように変更します。 具体的には、改行文字を <br> という文字に変更しておき、 プラグイン側で改行文字に復元します。 LANG:php // $body = get_source($base); $lines = get_source($base); for($i=0;$i<count($lines);$i++) if (preg_match('/\&tchart\(/', $lines[$i]) ) while(!preg_match('/\&tchart\(.*?\)\;/', $lines[$i]) && ($i+1<count($lines))) array_splice($lines, $i, 2, chop($lines[$i]) . '<br>' . $lines[$i+1] ); $body = convert_html($lines); * plugin/tchart.inc.php [#ge40e5b5] - 引数を連結して1つの文字列にする - <br> を改行に戻す - キャッシュされたファイルが無いか探す -- 無ければソースを tchart-svg.rb へ渡して結果をキャッシュする -- あればキャッシュを読み出す - そのまま SVG コードを返す -- ソースを tchart.rb へ渡して表示する LANG:php(linenumber) <?php // 画像ファイルのキャッシュ場所 define('TCHART_DIR', 'tchart'); function tchart($source) { $descriptorspec = array( 0 => array("pipe", "r"), // stdin 1 => array("pipe", "w"), // stdout 2 => array("file", "/dev/null", "a") // stderr ); $process = proc_open('/usr/local/bin/tchart-svg.rb', $descriptorspec, $pipes); $process = proc_open('/usr/local/bin/tchart.rb', $descriptorspec, $pipes); if (is_resource($process)) { fwrite($pipes[0], $source); fclose($pipes[0]); $result = stream_get_contents($pipes[1]); fclose($pipes[1]); proc_close($process); } return $result; } # 結果をキャッシュしたければこちらを呼び出す function tchart_cached($source) { $result = ''; $image_base = sha1($source); $image_dir = TCHART_DIR . "/{$image_base[0]}/{$image_base[1]}"; $image_svg = "{$image_dir}/{$image_base}.svg"; if(!file_exists($image_svg)) { $svg = tchart($source); if (mb_substr($svg[0],0,4)=="<svg") { if(!file_exists($image_dir)){ mkdir($image_dir, 0770, true); } $fh = fopen($image_svg, "w"); fwrite($fh, join("", $svg)); fclose($fh); } } else { $svg = file($image_svg); } return $svg; } function plugin_tchart_inline() { $args = func_get_args(); $source = join(",", $args); $source = preg_replace('/<br>/', "\n", $source); return tchart_cached($source); return tchart($source); } ?> * コメント・質問 [#f37cb237] #article_kcaptcha
Counter: 3739 (from 2010/06/03),
today: 3,
yesterday: 2