ソフトウェア/pukiwiki/tchart.inc.php のバックアップ(No.1)

更新


公開メモ

タイミング図を書きたい

デジタル信号処理の記事を書くのに、

&tchart( clock _~_~_~_~_~_~_~_~_~_~_ data =====X=DATA========X===== valid ~~~~~~~~~~_ ready ________~~_ );

こういったタイミング図を書きたくて、 プラグインにしてみました。

tchart

というツールを熊谷正朗さんが公開しておられます。

このツールを使うと、

clock	_~_~_~_~_~_~_~_~_~_~_
data	=====X=DATA========X=====
valid	_____~~~~~~~~~~______
ready	_____________~~______

こんな風にテキストで書いたタイミング図を、

&tchart( clock _~_~_~_~_~_~_~_~_~_~_ data =====X=DATA========X===== valid ~~~~~~~~~~_ ready ________~~_ );

このように図にすることができます。

ツール自体はテキストからポストスクリプト(eps)を出力するのですが、 そのままだとホームページに表示できないので、svg に変換するコードを別途書いています。

処理の流れ

  1. pukiwiki.php を変更して tchart プラグインに複数行にわたる引数を入力できるようにする
  2. 外部ツール tchart を呼び出して eps を作成
  3. ps2pdf で pdf に変換 https://packages.debian.org/cgi-bin/search_contents.pl?word=ps2pdf
  4. pdf2svg で svg に変換 https://packages.debian.org/search?keywords=pdf2svg
  5. ruby で書いたプログラムで svg の余白をトリミングする
  6. 変換結果の svg をファイルのキャッシュする
  7. html に直接埋め込んで表示する

svg ファイルを作るまでの処理

$ tchart chart.tc chart.eps
$ ps2pdf chart.eps chart.pdf
$ pdf2svg chart.pdf chart.svg

tchart ソースから svg を作り、余白をトリミングするスクリプト

本当なら tchart 自体を svg を出力する形に手直しをすれば良いのですが、 ここでは手抜きをしています。

LANG:ruby(linenumber)
#!/usr/bin/ruby

require "digest/md5"
require "tempfile"

##################################################### SVG を作る

source = readlines.join('')

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 の変更

標準ではプラグインに渡す引数に改行文字を入れられないので、 tchart プラグインに限って改行入りの引数を渡せるように変更します。

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);

Counter: 3755 (from 2010/06/03), today: 4, yesterday: 0