gtk实现图片旋转

⌚Time: 2022-08-03 20:23:37

👨‍💻Author: Jack Ge

使用cairo库的cairo_rotate函数对绘制内容进行旋转。但是旋转是围绕原点进行的。以窗口左上角为原点,水平和垂直方向为x、y轴建立的坐标系,这并不是我们想要的效果。我想让图片在窗口中的任意位置进行旋转

我想到的办法就是将绘制的图片移动,使其中心与坐标原点重合,这样就可以实现图片围绕自身进行旋转了,但是这样在窗口中只能显示左上角的一部分旋转图像

这时候就用到cairo_translate这个函数,它的功能就是平移坐标系,将坐标系移动到窗口任何你想显示的位置,在这里就相当于移动图片的位置了!

实现过程


#include <gtk/gtk.h>

#include <cairo.h>

#include <math.h>

guint timer_0;

int angle=0;

gboolean move_point(GtkWidget *widget){

    cairo_t *cr;

    cr = gdk_cairo_create (widget->window);

    

//  cairo_set_source_rgb(cr, 0, 0, 0);

//  cairo_rectangle(cr, 0, 0, 300, 200);

//  cairo_stroke_preserve(cr);

//  cairo_fill(cr);

    

    GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file("bg.jpg", NULL); 

    // 指定图片大小

    GdkPixbuf* dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, 100, 100, GDK_INTERP_BILINEAR);

    //平移

    cairo_translate(cr,200, 100);

    //旋转

    cairo_rotate(cr,M_PI*angle/180);

    angle++;

    if(angle > 360){

        angle = 0;

    }



    // dst_pixbuf作为cr环境的画图原材料,(0, 0):画图的起点坐标

    //将图片绘制到坐标原点位置

    gdk_cairo_set_source_pixbuf(cr, dst_pixbuf,-gdk_pixbuf_get_width(dst_pixbuf)/2, -gdk_pixbuf_get_height(dst_pixbuf)/2);

    cairo_paint(cr);    // 绘图

    //释放资源

    g_object_unref(dst_pixbuf);

    g_object_unref(src_pixbuf);

    cairo_destroy (cr);



    return TRUE;

}



int main(int argc,char* argv[]){





    GtkWidget* window;

    gtk_init(&argc,&argv);

    //创建新窗口

    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_window_set_title(GTK_WINDOW(window),"Demo");

    gtk_window_set_default_size(GTK_WINDOW(window),300,200);

    //关联窗口关闭回调函数

    g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);

    //设置窗口可绘制

    gtk_widget_set_app_paintable(window,TRUE);

    //显示窗口

    gtk_widget_show_all(window);

    //启动定时器

    timer_0 = g_timeout_add(3,(GSourceFunc)move_point,window);



    gtk_main();

 

    return 0;

}


等等,这个球是啥?

原来是画面重复旋转绘制,多个图像重叠造成的。只需要将代码注释部分加上就可以了。每次绘制之前清空屏幕


//  cairo_set_source_rgb(cr, 0, 0, 0);

//  cairo_rectangle(cr, 0, 0, 300, 200);

//  cairo_stroke_preserve(cr);

//  cairo_fill(cr);

这是正确的效果

另外,由于重复擦除屏幕与绘制图像,会有闪烁效果,如果要消除这种结果,就需要使用双缓冲技术绘图。

双缓冲的原理就是将图像绘制到缓冲区,再将缓冲区中的图像一次性绘制到窗口中,而不是先擦除窗口再进行绘制,这样就消除了闪烁效果