[Armadillo:06685] Re: GDK 画像表示の縮小でのメモリ問題

MasakiAoyama email@hidden
2011年 1月 31日 (月) 13:09:02 JST


青山です。

>  - g_pixbuf_base_image: 原寸サイズの元イメージのpixbuf (global 変数)
>  - pixbuf: gdk_pixbuf_render_to_drawable用の一時的な pixbuf
> 
> という用途に使おうとしているわけですよね?
> 
> たぶん image_expose_event() の中で毎回 pixbuf を生成していては、速度的
> に遅いため、一時的なバッファとしての pixbuf を引数で渡しているのだと想
> 像しました。ところが、gdk_pixbuf_scale_simple()は、スケールしたpixbuf

webに転がってる画像表示の参考ソースから見よう見まねでやりました。

pixbuf = gdk_pixbuf_new_from_file("image.xpm", &err);
g_signal_connect (GTK_OBJECT (drawing_area), "expose_event", 
					GTK_SIGNAL_FUNC(expose_event), pixbuf);
としておいて、

gtk_widget_queue_draw (GTK_WIDGET(drawing_area));
を呼んだら、

gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
が呼ばれて、引数dataをpixbufのポインタに入れて再描画する。という。
GdkPixbuf *pixbuf = (GdkPixbuf *)data;
gdk_pixbuf_render_to_drawable (pixbuf, widget->window,
                                 widget->style->fg_gc[GTK_STATE_NORMAL],
                                 0, 0, 0, 0,
                                 gdk_pixbuf_get_width(pixbuf),
                                 gdk_pixbuf_get_height(pixbuf),
                                 GDK_RGB_DITHER_NORMAL, 0, 0);

gdk_pixbuf_new_from_fileで作成したpixbufの領域をg_signal_connectで関連づ
けといて、expose_event内で使ってるってことですね。

> であれば、scale する時に新しい pixbuf を生成しない gdk_pixbuf_scalel()
> を使うというのはどうでしょうか? 新しく pixbuf を生成しない、つまりメモ

やってみました。

gdk_pixbuf_scale(g_pixbuf_base_image, pixbuf, 
                 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0, 
                 (IMAGE_WIDTH/IMAGE_BASE_WIDTH),
                 (IMAGE_HEIGHT/IMAGE_BASE_HEIGHT), GDK_INTERP_NEAREST);

これでうまく行きました。

> ちなみに、scale しないのであれば、わざわざ一時的な pixbuf に copy しな
> くても、gdk_pixbuf_render_to_drawable() でオフセットを指定すれば
> widget->window に直接 g_pixbuf_base_image の一部を書き込むことが
> できますよ。オフセットは第4引数と第5引数です。

これも確認できました。gdk_pixbuf_copy_areaを使わずに済ませますね。

無駄なアクション減らせて、「本来こうするべき」な形になりました。
どうもありがとうございました。

以上


Yasushi SHOJI <email@hidden> wrote:

> At Fri, 28 Jan 2011 14:15:39 +0900,
> MasakiAoyama wrote:
> > 
> > 先ほどのソースで、gdk_pixbuf_render_to_drawableのあとに
> > 
> > gdk_pixbuf_unref (pixbuf);
> > 
> > とだけ書いてたら落ちるので、てっきりやったらいかんのかと思ってしまってま
> > したが、
> > gdk_pixbuf_scale_simpleのときは新しく作ってるから解放がいるが、
> > gdk_pixbuf_copy_areaのときはやらなくていい(表示に使っているのをそのまま
> > 使っている?)
> > ってことだったんですね。
> 
> その通りですね。
> 
> image_expose_event()をどのように呼び出しているか分らないので、なんとも
> 言えませんが適当に考えてみました。コードの中には g_pixbuf_base_image,
> pixbuf という二つの変数があり、それぞれ
> 
>  - g_pixbuf_base_image: 原寸サイズの元イメージのpixbuf (global 変数)
>  - pixbuf: gdk_pixbuf_render_to_drawable用の一時的な pixbuf
> 
> という用途に使おうとしているわけですよね?
> 
> たぶん image_expose_event() の中で毎回 pixbuf を生成していては、速度的
> に遅いため、一時的なバッファとしての pixbuf を引数で渡しているのだと想
> 像しました。ところが、gdk_pixbuf_scale_simple()は、スケールしたpixbuf
> のコピーを新しく生成し、その pixbuf へのアドレスを戻してしまうため、今
> 回のリークに繋っています。
> 
> 逆に gdk_pixbuf_copy_area() では、渡された元 pixbuf の一部を、書き込み
> 先 pixbuf にコピーするという処理をします。そのため、新しい pixbuf が生
> 成されるわけではありません。それなのに、unref してしまうと次の expose
> 時に unref された pixbuf を使おうとして落ると思います。
> 
> であれば、scale する時に新しい pixbuf を生成しない gdk_pixbuf_scalel()
> を使うというのはどうでしょうか? 新しく pixbuf を生成しない、つまりメモ
> リの確保を行なわないので処理が(ほんの少しだけ)早くなりますし、copy 時と
> 同じように「渡された pixbuf を一時的なバッファとして使う」ことができる
> のではないでしょうか?
> 
> ちなみに、scale しないのであれば、わざわざ一時的な pixbuf に copy しな
> くても、gdk_pixbuf_render_to_drawable() でオフセットを指定すれば
> widget->window に直接 g_pixbuf_base_image の一部を書き込むことが
> できますよ。オフセットは第4引数と第5引数です。
> 
> scale しながら drawable に書く処理は、前に探したときになかったように記
> 憶しています。間違ってたらごめんなさい。
> -- 
>             yashi
> 
> _______________________________________________
> armadillo mailing list
> email@hidden
> http://lists.atmark-techno.com/cgi-bin/mailman/listinfo/armadillo


----------------------------------
株式会社 レイトロン 新事業推進部
 青山 真樹  email@hidden




armadillo メーリングリストの案内