GdkPixbufを高速にリサイズ(cairo)


GdkPixbufのサイズ変更を、元画像500x500px から 出力画像100x100~10x10pxで行うと、どうやらとても遅くなるようです。



GDK_POINTER_MOTION_HINT_MASK を使わずに motion-notify-eventをそのまま再描画に投げている私も悪いのですが。
とはいえ GDK_POINTER_MOTION_HINT_MASK はGtk3で思った通りにならず、アプリケーションがフリーズするようになっていました。

将来的には描画前のレンダリングをマルチスレッド化するつもりではいます。しかしシングルスレッドだと競合などを考えずに済み楽であるため、どうにもならなくなるまではシングルスレッドで行くつもりです。

というわけで、単純にリサイズ機能を高速化して対応。このあたりも、cairo任せにするといろいろオブジェクトを確保するコストを考えてもずっと早いのではないかというカンが当たった感じです。


なお、 gdk_pixbuf_scale_simple()をそのまま、画質を GDK_INTERP_HYPER からバイリニア指定に変えるのは試してみましたが、ほとんど効果なしでした。

なお画質は不明。見た目にわからないですし悪くないですが、アプリケーションが将来的に画質を指定するようになったら、リサイズ機能を見直そうと思います。

呼び出し例は以下。
====
/*

 
GdkPixbuf *pb = gdk_pixbuf_scale_simple(

 

 

 
pixbuf,

 
 
 
(int)w, (int)h,
 
 
 
GDK_INTERP_HYPER);
*/

 
GdkPixbuf *pb = _pv_copy_new_pixbuf_scale(
 
 
 
pixbuf,
 
 
 
(int)w, (int)h);
====

実装は以下。
====
static GdkPixbuf *_pv_copy_new_pixbuf_scale(GdkPixbuf *pb_src, double w_dst, double h_dst)
{
 
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w_dst, h_dst);
 
pv_assert(surface);
 
cairo_t *cr = cairo_create (surface);
 
pv_assert(cr);

 
double w_src = gdk_pixbuf_get_width(pb_src);
 
double h_src = gdk_pixbuf_get_height(pb_src);

 
cairo_matrix_t m = {
 
 
w_dst/w_src, 0,
 
 
0, h_dst/h_src,
 
 
0, 0,
 
};
 
cairo_set_matrix(cr, &m);

 
gdk_cairo_set_source_pixbuf (cr, pb_src, 0, 0);
 
cairo_paint (cr);

 
GdkPixbuf *pb = gdk_pixbuf_get_from_surface(surface, 0, 0, w_dst, h_dst);
 
pv_assert(pb);

 
cairo_surface_destroy (surface);
 
cairo_destroy (cr);

 
return pb;
}
====

作ったPixbufは呼び出し元で開放しましょう。
以上です。

TIGORA(ティゴラ)のトレッキング シューズ

 TIGORA(ティゴラ)の トレッキング シューズを買いました。 メインの靴がアシックスウォーキングで街歩き用なのですが、これまではこれで高尾山などの軽い山も登っていました。 今回、靴底があまりに摩耗したこともあってアシックスウォーキングを買い替えたのですが、ついでに消耗が激...