GIMP のなかみ


ある事情から GIMP の内部構造をある程度調べねばならなくなり, xcf ファイルフォーマットあたりから手を付けている. ghex という GNOME のバイナリエディタがあるが, これを使って xcf ファイルを解析 (つうほどのもんでもないが) ないしは, ぼーっと眺めていると色んなことが解る.

ここでネタをばらしても誰も見てねえだろうから, 自分のためのノートがてらに書くと, xcf には parasite というのがある. これはイメージや drawable につくプロパティの一つで, プラグインなんかの使うデータを drawable (レイヤとか チャネルとか) のプロパティとしてセーブしておけるものだ. たとえば dynamic text は文字やフォントの情報を憶えているが, これはレイヤのプロパティとして dynamic text の parasite が xcf に保存されているのだ. 他には, ifs プラグイン (フラクタルで樹なんかを描けるアレ) のデータなどが, こうしてセーブされる. parasite というプロパティは v.1.0.x には無いが, 無いプロパティは xcf ファイルのローダが単に

unexpected/unknown image property: 21 (skipping)

などといって無視するだけで, 普通に読み込むことができる. 21番のプロパティは parasite である.

プロパティには, レイヤの場合, 他にもいろいろあるが, レイヤの透明度 (guint32型) 可視性 (目玉マークのアレ, gboolean) オフセット (guint32) モード (忘れた) などがある. ほかにも, レイヤ窓に出て来る性質は, 全部こうして 保存されるのだ. 新しいプロパティを追加するには, app/xcf.c に, 対応するプロパティを 作り, 読み書きする関数を書き, そのプロパティを扱うハンドラを どこぞで定義することになる (そんな簡単に言うな) .

レイヤにもプロパティがあるように, イメージ (レイヤ, チャネル, その他から なる, GIMP の画像データの塊) にもプロパティがある カラーマップ, ガイド, 解像度, タイプ(RGB とか RGBA とか)なんかがある. カラーマップが保存できるかどうかは, 扱える xcf のバージョンによる. プロパティの追加は後方互換性を損なわずにできるので, わりと良い感じ.

xcf にもバージョンがあるのです. 知ってましたか? xcf ファイルのバージョン番号は 普通の RGBA イメージなどなら 0. (知らないプロパティがあっても 関係なく 0 のままだ!) color map 付きの indexed image ならバージョンは 1. バージョン番号に 2 以上が付いてたら エラーになる (1.1.18). 別に, 1.2 系が使うファイルだから バージョン番号が増えるということは ないのである. でたらめなバージョン番号を付けて試せるところが ghex の偉大なところだ.

そうそう. xcf の圧縮形式も実装されようとしているぞ. ただ, 今はどれも使えないんだけど. (xcf.gz とは違います. あれは外部プログラムを使って圧縮しているだけです.) 画像データの本体というか, ビットマップ情報を 担っているデータ型である, タイルのところを圧縮しようとしているわけです. RLE 圧縮のところはコードが書いてあるが, 使えるようにはなっていない. 他に, zlib や fractal も書いてあるが, これらは書いてあるだけ.

タイル!タイル!タイル!

GIMP を理解する最大のキーワードがこれだ. 画像データ (drawable) は, 全て tile という形で扱われる. しかし, こいつに関しては現在調査中故, 詳細は次回 (ってあれば, の話だがな)ということで.

そうそう. タイル キャッシュ サイズという設定があるが, これの計算法を紹介しよう. タイルをキャッシュしておくのに使うメモリのサイズがこれで決まるのである. この値は原則として GIMP がメモリを独占するまで増やして良し. である. いや, もちろん, ほかにユーザが沢山いるシステムでそういうことをしたら パフォーマンスに重大な影響を及ぼすのでアレですが, stand alone で あなたの GIMP しか動いていない, というパソコン状態な場合は, GIMP にメモリを独占させてやろう. ところで キャッシュされてないタイルはどこにあるかというと, .gimp-hoge/gimpswap??? に存在しているわけだ. GIMP は独自のアドレス変換によって, 自前で画像データ専用仮想メモリシステムを用意しているのだ.

タイルキャッシュサイズにしたがって, GIMP 独自の swap が始まる. 事前 swap がどのようにして開始されるのかは, ちょっとみたところ 解らんが, メモリが足りなくなって始まる intensive swap は 現在使用中のキャッシュが gimprc で設定した 値に あと 64*64*4 bytes (最大 タイルサイズ) というところまで接近したら, 開始されるのだ. このとき, cache に使う GIMP の確保しているメモリがシステムの用意した swap 領域(/sbin/swapon されるアレ) にはみ出してたら, swap パーティションと ~/.gimp-1.1/gimpswap.1234 の間をタイルが 右往左往することになり, 絶大なパフォーマンスの低下を招くので, でかくしすぎるとだめ. まあ, それでも swap は別スレッドなので 1.0 の時みたいに 完全に固まってしまうということは無いのですが.

ピクセルあたりの深度を増やすと, このへんのコードをだいぶ書き直さねば ならないだろう. (tile.c, tile_cache.c, tile_swap.c xcf.c) プラグインも影響を被るものが沢山でてくるかも. えらいこっちゃ. 次回はこのへんを追求できるといいですね.