用 cairo 旋转图像 Gtk 3

Rotate Image Gtk 3 with cairo

我正在尝试让图像在随机位置旋转。我在看另一个类似的 post(rotate image)。但我无法让事情正常进行。

#include <gtk/gtk.h>
#include <cairo.h>

GtkWidget *window;

static void rotate_cb()
{
    gtk_widget_queue_draw(window);

}

static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
    GtkWidget *img = (GtkWidget *)(data);
    gint w = gtk_widget_get_allocated_width (img);
    gint h = gtk_widget_get_allocated_height (img);
    gtk_widget_realize(img);
    cairo_surface_t *surface = gdk_window_create_similar_surface(gtk_widget_get_window (img), CAIRO_CONTENT_COLOR, w, h);
    cairo_t *cr = cairo_create (surface);

    cairo_translate(cr, w/2, h/2);
    cairo_rotate(cr, 2);
    cairo_set_source_surface(cr, surface, -w/2, -h/2);

    cairo_paint(cr);
    cairo_destroy(cr);
    cairo_surface_destroy(surface);
    return FALSE;
}


int main(int argc, char *argv[])
{   
    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
    gtk_widget_set_app_paintable(window, TRUE);
    GtkWidget *l = gtk_layout_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(window), l);
    GtkWidget *img = gtk_image_new_from_file("example.png");
    gtk_layout_put(GTK_LAYOUT(l), img, 300, 300);

    g_signal_connect(window, "draw", G_CALLBACK (on_expose_event), img);
    g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);

    GtkWidget *button = gtk_button_new_with_label("button");
    g_signal_connect(button, "clicked", G_CALLBACK(rotate_cb), NULL);
    gtk_layout_put(GTK_LAYOUT(l), button, 0, 0);

    gtk_widget_show_all(window);
    gtk_main();
}

window确实收到了绘图信号,但我不知道如何连接gtkwidget和cairo_surface_t。

或者也许有更好的方法来做到这一点(没有开罗)。我喜欢各种各样的想法!谢谢!

GtkWidget draw 信号处理程序原型应该是:

gboolean user_function (GtkWidget *widget, CairoContext *cr, gpointer user_data)

documentation所述:

This signal is emitted when a widget is supposed to render itself. The widget 's top left corner must be painted at the origin of the passed in context and be sized to the values returned by gtk_widget_get_allocated_width() and gtk_widget_get_allocated_height().

Signal handlers connected to this signal can modify the cairo context passed as cr in any way they like and don't need to restore it. The signal emission takes care of calling cairo_save() before and cairo_restore() after invoking the handler.

The signal handler will get a cr with a clip region already set to the widget's dirty region, i.e. to the area that needs repainting. Complicated widgets that want to avoid redrawing themselves completely can get the full extents of the clip region with gdk_cairo_get_clip_rectangle(), or they can get a finer-grained representation of the dirty region with cairo_copy_clip_rectangle_list(). Parameters

widget - the object which received the signal

cr - the cairo context to draw to

user_data - user data set when the signal handler was connected.

因此您的 on_expose_event 函数原型必须更改并且 cairo 上下文将提供给您:

static gboolean on_expose_event(GtkWidget *widget, cairo_t *cr, gpointer data)
{
.... // your code must change too
}