ワールドカップ出場記念で英語をいっぱい書いてみた

graphvizで日本語を出す話はいろいろ聞くけれど、にんとも上手く動かなかったのでいろいろやった、その結論。
あ、環境は

%uname -sr
FreeBSD 5.4-RELEASE-p1
%pkg_info|fgrep graphviz
graphviz-2.2        Graph Visualization Software from AT&T and Bell Labs
%dot -V
dot version 2.2 (Wed Jun  8 13:51:09 UTC 2005)

です。

書き方

UTF-8で書く。心配なら

digraph G {
    graph [charset="UTF-8"]
}

とでもしておく。でもデフォルトがUTF-8だから、そこまでせんでも。
あと、日本語フォントを指定する。例えば

digraph G {
    日本語 [fontname="mona"]
}

フォントの指定

graphvizがfontconfigに対応している場合は"mikachan"とか"Sazanami Gothic"とか適当に指定する。
対応していない場合はフォントファイルを直接指定する。例えばみかちゃんフォントなら

%dot test.dot -Nfontname=mika -Nfontpath=/usr/X11R6/lib/X11/fonts/TrueType -Tpng

とやれば、/usr/X11R6/lib/X11/fonts/TrueType/mika.ttfを使ってくれる。

graphvizとfontconfig

graphvizはfontconfigに対応しているが、FreeBSDのportをそのまま使うとこれが有効にならない。
graphvizのconfigureはfontconfig-confというプログラムが見つかれば自力でfontconfigを発見するのだが、これはFreeBSDでは見つからない(そもそも存在するんだろうか?)。だからconfigureのオプションでfontconfigのヘッダーとライブラリの場所を直接教えてあげる必要がある。
面倒なのでportのMakefileを直接書き換えた:

*** Makefile.org  Thu Jun  9 02:03:41 2005
--- Makefile    Wed Jun  8 22:49:00 2005
*************** MLINKS=         dot.1 circo.1 \
*** 51,56 ****
--- 51,61 ----
  MYPORTDOCS=   dotguide.pdf dottyguide.pdf leftyguide.pdf \
                neatoguide.pdf Dot.ref FAQ.html
  
+ .if defined(WITH_FONTCONFIG)
+ CONFIGURE_ARGS+=--with-fontconfigincludedir=${X11BASE}/include \
+               --with-fontconfiglibdir=${X11BASE}/lib 
+ .endif
+ 
  post-install:
  .if !defined(NOPORTDOCS)
        @${MKDIR} ${DOCSDIR}

ちょっとかっこつけてWITH_FONTCONFIGで選択可能にしてみた :-)
で、これでmake WITH_FONTCONFIG=yesすればfontconfigに対応したgraphvizのできあがり。
この話はとりあえずfreebsd-questionsに投げてみた。問題なさそうならport maintainerに連絡したいな。

dotがカタカナで落ちる問題

さて、これでばりばり日本語のグラフを作っていたら、いくつかdotがクラッシュするものが見つかった。某所では「GDかiconvのバグ」と出ていたけど、調べたらどうやらdotのバグらしいことが分かった。
以下は御本家に出したバグレポート:

Title: Memory exhaust with UTF-8 Japanese Katakana

Description of problem:
Using japanese katakana(U30A0-U30FF) characters causes memory exhaust in label_size() in dotneato/common/labels.c.
label_size() function has a workaround for Big5 charset and it makes some input characters skip when their codes are in range 0xA1-0xFE.
Unfortunately, japanese katakana characters are represented as byte sequence 0xE382A0-0xE383BF in UTF-8, some of their last byte in the range above.
So the workaround casts head position of input (variable p) over the null-terminator, then the while loop will go infinite.
This problem would happen in other than japanese katakana characters, but I haven't checked.

Fix:
The following patch works fine for me:

*** dotneato/common/labels.c    Thu Jun  9 00:53:40 2005
--- dotneato/common/labels.c.new        Thu Jun  9 00:53:31 2005
*************** static pointf label_size(char *str, text
*** 60 ****
--- 61 ----
+     size_t len;
*************** static pointf label_size(char *str, text
*** 67 ****
!     line = lineptr = N_GNEW(strlen(p) + 1, char);
--- 68 ----
!     line = lineptr = N_GNEW(len = strlen(p) + 1, char);
*************** static pointf label_size(char *str, text
*** 69 ****
!     while ((c = *p++)) {
--- 70 ----
!     while (p < str + len && (c = *p++)) {

ちなみに問題が起こるのは、UTF-8で任意のカタカナ5文字をラベルに使ったとき。前後に1文字でも追加すれば問題は起こらない。びみょー。
今気が付いたけど、メモリが尽きるんじゃなくて変なメモリを読みに行くバグだな。あちゃあ。

追記

いやあ、反応はやいぞgraphviz
Bug 671としてワーキングコピーではすでに修正済みとのこと。あららら。
でもまあ、次のリリースまで待てない人(それは私)には今すぐ必要なんだから、いいか。
せっかくなのでCVSから落としてきて確認してみた。
なーるほど、明示的にcharsetがBig5に指定されているときだけBig5用の回避ルーチンを使うわけね。ふーむ、まあ妥当ではあるけど…。
ちゃんちゃん。