如何从Cairo曲面创建GtkImage?

4urapxun  于 2023-04-19  发布在  其他
关注(0)|答案(3)|浏览(159)

我希望能够使一个GtkImage从开罗表面(没有写一个临时文件)。
我目前将表面作为PNG写入一个char数组,然后将其馈送到PixbufLoader以获得Pixbuf,我使用它来创建GtkImage:

typedef struct
{
    unsigned char *pos;
    unsigned char *end;
} closure_t;

static cairo_status_t
png_to_array (void *closure, const unsigned char *data, unsigned int length)
{
    closure_t *cl = (closure_t *) closure;

    if ((cl->pos + length) > (cl->end))
        return CAIRO_STATUS_WRITE_ERROR;

    memcpy (cl->pos, data, length);
    cl->pos += length;

    return CAIRO_STATUS_SUCCESS;
}

// later in the code
cairo_surface_t *surface = ...

...

// how would i determine the right size?
unsigned char arr[...];
closure_t cl;
GtkWidget *image;
GdkPixbufLoader *pbloader;
GdkPixbuf *pb;

// copy surface png to arr
cl.pos = arr;
cl.end = arr + sizeof(arr);
cairo_surface_write_to_png_stream (surface,
                    (cairo_write_func_t) png_to_array,
                    &cl);

...
// write to pixbufloader, get pixbuf, create image
pbloader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(pbloader, arr, sizeof(arr), NULL);
gdk_pixbuf_loader_close(pbloader, NULL);

pb = gdk_pixbuf_loader_get_pixbuf(pbloader);

image = gtk_image_new_from_pixbuf(pb);

1.这似乎相当麻烦-有没有更简单的方法来做到这一点?
1.在我的例子中,我如何确定数组的大小?

pod7payv

pod7payv1#

这里有一个函数可以帮你节省很多精力。查看gdk_pixbuf_get_from_surface。它从cairo_surface_t中获取Pixbuf。粗略地说,当他编写它时,只有当你使用Gdk-3.0时才可用,这也意味着使用Gtk+-3.0。
如果你想使用Gtk+-2.0,你可以创建一个pixmap,从它得到一个cairo_t,然后复制你的其他cairo_surface_t到它。

cairo_set_source_surface (cr, surface, x0, y0);
cairo_rectangle (cr, x0 + x, y0 + y, width, height);
cairo_fill (cr);

下面是一个如何创建pixmap的例子,我会让你填写剩下的。

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

int main(gint argc, gchar *argv[])
{
    GdkPixmap *pixmap;
    GtkWidget *image;
    GtkWidget *window;
    cairo_t *cr;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(window);

    pixmap = gdk_pixmap_new(window->window, 100, 100, -1);
    cr = gdk_cairo_create(pixmap);
    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);    
    cairo_rectangle(cr, 10, 10, 80, 80);
    cairo_fill(cr);
    cairo_destroy(cr);

    cr = NULL;


    image = gtk_image_new_from_pixmap(pixmap, NULL);

    gtk_container_add(GTK_CONTAINER(window), image);

    gtk_widget_show(image);


    gtk_main();

    return 0;
}
lo8azlld

lo8azlld2#

只是一个提示,我不知道如何确定数组的大小,但我确定数组的大小应该是多长,因为你的png_to_array回调将被调用几次数组的大小应该是所有长度的总和
我使用stride来确定数组的大小,但是在最后total_lenght将确定png的大小

int total_lenght = 0;

typedef struct
{
    unsigned char *pos;
    unsigned char *end;
} closure_t;

static cairo_status_t
png_to_array (void *closure, const unsigned char *data, unsigned int length)
{
    closure_t *cl = (closure_t *) closure;

    if ((cl->pos + length) > (cl->end))
        return CAIRO_STATUS_WRITE_ERROR;

    memcpy (cl->pos, data, length);
    cl->pos += length;

    total_lenght += lenght;

    return CAIRO_STATUS_SUCCESS;
}

// later in the code
cairo_surface_t *surface = ...

...

int stride = cairo_image_surface_get_stride(surface);

unsigned char *arr = (unsigned char *) malloc(stride);
closure_t cl;
GtkWidget *image;
GdkPixbufLoader *pbloader;
GdkPixbuf *pb;

// copy surface png to arr
cl.pos = arr;
cl.end = arr + stride;
cairo_surface_write_to_png_stream (surface,
                    (cairo_write_func_t) png_to_array,
                    &cl);

...
// write to pixbufloader, get pixbuf, create image
pbloader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(pbloader, arr, total_lenght), NULL);
gdk_pixbuf_loader_close(pbloader, NULL);

pb = gdk_pixbuf_loader_get_pixbuf(pbloader);

image = gtk_image_new_from_pixbuf(pb);
jaxagkaj

jaxagkaj3#

如果你使用的是Gtk3,那么你可以使用函数new_from_surface
只是为了展示你如何实现你想要做的事情,基本上你走在正确的道路上,使用realloc进行动态分配:

typedef struct
{
    size_t length;
    unsigned char *data;
} png_buffer;

static cairo_status_t
png_to_buffer (void *closure, const unsigned char *data, unsigned int length)
{
    png_buffer *buff = (png_buffer *)closure;
    buff->data = (unsigned char *)realloc(buff->data, sizeof(unsigned char) * (buff->length + length)); // We reallocate the buffer
    memcpy( // Copy the data to the buffer considering the offset
        &(buff->data[buff->length]), // This is the same as buff->data + buff->length
        data,
        sizeof(unsigned char) * length
    );
    buff->length += length;
    return CAIRO_STATUS_SUCCESS;
}

// later in the code
cairo_surface_t *surface = ...

...
png_buffer png_data = {
    .length = 0,
    .data = NULL // realloc will allocate the memory
};
GtkWidget *image;
GdkPixbufLoader *pbloader;
GdkPixbuf *pb;

// copy surface to png_buffer
cairo_surface_write_to_png_stream (surface,
                    (cairo_write_func_t) png_to_buffer,
                    (void *)&png_data);

...
// write to pixbufloader, get pixbuf, create image
pbloader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(pbloader, (guchar *)png_data.data, (gsize)png_data.length, NULL);
gdk_pixbuf_loader_close(pbloader, NULL);

pb = gdk_pixbuf_loader_get_pixbuf(pbloader);

image = gtk_image_new_from_pixbuf(pb);

相关问题