Jan.04.2000
GdkPixbuf の基本とその使用方法。
主に画像ファイルのローダーとしての GdkPixbuf と、Imlib と比べて
なにができるライブラリなのかの把握。
GdkPixbuf は Gnome プロジェクトにおいて現在使用されている Imlib の
代換となるべく開発されたライブラリです。つまり、次の Gnome では
Imlib を使わなくて済むようにしようと、Gnome のお膝もとで作られた
ライブラリということです。
これを書いている時点(Mar.06.2000)での GdkPixbuf のバージョンは 0.6.0
で、まだ Imlib と同等の全機能を備えているわけではありませんが、
必要な部分はおおよそそろっています。
さて GdkPixbuf、そして Imlib は何をしてくれるライブラリなのでしょうか。
基本的にはフレームバッファの提供とその操作です。X client Apprication に
対し、client 側で管理する 24bit Color (α付きで32bit)のメモリーワークと
いったところです。client 側で操作するフレームバッファなので画像の加工や
直接的な操作が出来ます。その分いちいち server へ変換・転送しなくては
なりませんから表示速度は若干弱くなります。
基本はフレームバッファ間での画像加工なのですが、Imlib が持っている
優れた特色に画像ファイルの読み込みがあります。これがとても便利な事が
Imlib が使われ続けて来た理由だと思われます。アプリケーションは
Imlib にファイル名を渡すだけで、Imlib が適した画像lib を選んで使い、
フレームバッファに画像を展開してくれます。
もちろん GdkPixbuf もこの画像ファイル読み込み部分をばっちり持っています。
画像を読んで表示するだけならばかなり少ないコードで記述できてしまいます。
実は Gdk には GdkImage というフレームバッファ管理の関数群が存在します。
なのに GdkPixbuf はそれを用いずにまた新たなフレームバッファ機構を
提供してしまいました。GdkImage と GdkPixbuf の違いはなんでしょうか?
私も完全に把握はしていないのですが、以下の点が違うようです。
GdkPixbuf の扱うフレームバッファを生成するには gdk_pixbuf_new を
使います。これで GdkPixbuf* を生成したあとはそのバッファに対して
色々と操作をします。
gdk_pixbuf_get_pixels(GdkPixbuf*) でフレームバッファのポインタを
獲得し、直接バッファ内を書き換えてデータ操作とかしても良いでしょう。
フレームバッファを X server に表示するためには、X server 側の
Drawable に適切な color depth に変換しつつ転送しなくてはなりません。
この作業を「レンダリング」といいます。
レンダリングするには
gdk_pixbuf_render_to_drawable_alpha, gdk_pixbuf_render_to_drawable,
gdk_pixbuf_render_threshold_alpha, gdk_pixbuf_render_pixmap_and_mask
といった関数を使います。用途は頭から「α付きのレンダリング」
「α無しのレンダリング」「αから2値化されたbitmapマスクのレンダリング」
「pixmap, bitmap へのレンダリング」となっています。
GdkPixbuf はファイル名を与えるだけでそのファイルを読み込み、型を
判別し、展開した後に GdkPixbuf* ポインタ(フレームバッファ)を返して
くれます。らくちんですね。
具体的には gdk_pixbuf_new_from_file(*filename) をコールするだけ。
おしまい。
画像ファイルの読み込みの際には、その画像フォーマットに対応した lib
が必要になります。(libtiff, libjepg, libpng など)それらは GdkPixbuf の
インストール前に入れておきましょう。
以上の仕組みを「りも時計」内にて実装したソースです
void ChangeFace(gchar *fname) { GdkPixbuf *chr; GdkGC *gc; gint w, h; chr = gdk_pixbuf_new_from_file(fname); if (chr != NULL) { w = gdk_pixbuf_get_width(chr); h = gdk_pixbuf_get_height(chr); RRMainWindowSize(w, h); RRScreenFree(); gtk_widget_set_usize (RRScreenWindow(), fw, fh); RRScreenInit(RRScreenWindow(), RRScreenCanvas(), fw, fh, TRUE); if (pic != NULL) gdk_pixmap_unref(pic); pic = gdk_pixmap_new(RRScreenCanvas()->window, w, h, -1); gc = gdk_gc_new(pic); gdk_pixbuf_render_to_drawable(chr, pic, gc, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0); RRScreenPutPixmap(pic, 0, 0); disp_time(); gdk_gc_destroy(gc); gdk_pixbuf_unref(chr); } }
ゲーム作成の実際を考えます。今、データが個別になっておらず、
拙作の rrda にてアーカイブ管理されているとします。この形式では
読みだした画像データはメモリ上にありポインタ経由で渡されます。
当然ファイルに落ちていませんから gdk_pixbuf_new_from_file は
使えません。
そんなときは GdkPixbufLoader を使います。
これはストリーム経由で順次画像を読み込み生成する機構で、WEBブラウザ
みたいに読み込み途中の絵が徐々に表示されるといった構造を実現できます。
これがメモリーバッファ内の画像データを解析してくれるので先のように
画像データがメモリーバッファ上にしかなくても画像を得ることができます。
先の「りも時計」の画像ロード部分を強引に GdkPixbufLoader 型に書き換えて
みた実験コードです。
void ChangeFace(gchar *fname) { GdkPixbuf *chr; GdkGC *gc; gint w, h; FILE *fp; long size; gchar *work; GdkPixbufLoader *loader; fp = fopen(fname, "r"); fseek(fp, 0, SEEK_END); size = ftell(fp); work = malloc(size); fseek(fp, 0, SEEK_SET); fread(work, sizeof(char), size, fp); fclose(fp); loader = gdk_pixbuf_loader_new(); if (gdk_pixbuf_loader_write(loader, work, size) == FALSE) { printf("error -=-=-\n"); } chr = gdk_pixbuf_loader_get_pixbuf(loader); if (chr != NULL) { w = gdk_pixbuf_get_width(chr); h = gdk_pixbuf_get_height(chr); RRMainWindowSize(w, h); RRScreenFree(); gtk_widget_set_usize (RRScreenWindow(), fw, fh); RRScreenInit(RRScreenWindow(), RRScreenCanvas(), fw, fh, TRUE); if (pic != NULL) gdk_pixmap_unref(pic); pic = gdk_pixmap_new(RRScreenCanvas()->window, w, h, -1); gc = gdk_gc_new(pic); gdk_pixbuf_render_to_drawable(chr, pic, gc, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0); RRScreenPutPixmap(pic, 0, 0); disp_time(); gdk_gc_destroy(gc); gdk_pixbuf_unref(chr); } }
今回はあまり詳しく取り上げませんが、画面を拡大縮小したり、コピーしたり
することができます。拡大縮小はどちらかと言えばサイズを変えながら
他の Pixbuf にコピーといった感じですので、転送結果保持用にもうひとつ
Pixbuf が必要です。もちろん、そのサイズ変更コピーと同時にαブレンディング
が使えますので色々とできそうです。
この画像加工周りは、MPU がインテルのもので MMX が使える場合 MMX を
利用してくれる様です。(実際にどこに使っているかまでは覗いていない)
GdkPixbuf はレンダリングに GdkRGB を使うというのは先に書いた通りです。
故に gdk_rgb_init(); を実行して GdkRGB を初期化していないとレンダリング
が実行できません。
実はここではまって一時間強を費した…(--;
コマがPixbuf内に敷き詰められている画像ファイルを用いてアニメーション
とするような管理構造体がありますけど、単に存在するだけで実際に用いる
ためには自分でコーディングしなければならないようです。おそらく
アニメーションGIF の代わりとなるように設計されているのでしょう。
(逆に言うとその程度の実装ですが)
Imlib とか GdkImage にもありますが、X server 側の Drawable を client 側
のフレームバッファに持って来る機能があります。フォント描画などは
X server に行わせると楽ですので、その結果を逆輸入してフレームバッファに
加工・適用とかいった使い方ができます。