Gdk pixbuf load image from memory

Matekk picture Matekk · Jan 2, 2013 · Viewed 9.7k times · Source

Using GTK+ 3.6 I would like to display an image from a buffer in memory, not a file on disk. I have a const char *data with the image data, and I'm trying to create a GTK image from it. So far I have tried two approaches which I thought could work. Both use GdkPixbuf, and thus require the image data to be guchar* (unsigned char*).

With that requirement I have to cast the data:

guchar *gudata = reinterpret_cast<guchar*>(const_cast<char*>(data));

I then tried the following:

  1. Writing the data into a GdkPixbufLoader with gdk_pixbuf_loader_write. Here I get an error "Unrecognized image file format" or if I create the loader with a specific type (jpg) i get an error saying that it's not a JPG file format (and it is, explained below).

    EDIT: A bit of code:

    guchar *gudata = reinterpret_cast<guchar*>(const_cast<char*>(data));
    int stride = ((1056 * 32 + 31) & ~31)/8;
    GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
    GError *error = NULL;
    
    if(!gdk_pixbuf_loader_write(loader, gudata, data_size, &error)
    { 
        printf("Error:\n%s\n", error->message); 
    }
    

    EDIT 03/01/2013: Removed stride parameter from write function - misprint.

    Cairo surface does not work as well. Shows black screen and noise.

  2. Initializing the pixbuf with gdk_pixbuf_new_from_data and then the image just looks like tv noise, which would indicate that either the data is wrong (and it has been cast), or that the other parameters were wrong (image row stride, but it's not :) ).

After errors I just tried writing the data to a file foo.jpg using ofstream and yes, I get a properly working image file. The file command in terminal confirms that it is a JPEG image, and with a simple block of code I've created a GdkPixbuf from that foo.jpg to check out it's row stride value and it matches the value I pass to the aforementioned function.

Does the image data become corrupt with the cast, and if so how can I address that? I get the image data in const char*. I have looked at QtPixmap and it also loads unsigned char*.

Do I need to use a seperate library? (libjpeg?) I have libgtk3-dev installed.

Thank you!

Answer

liberforce picture liberforce · Jan 2, 2013

03/01/2012 UPDATE:

Here's a simple working app that loads a "test.jpg" file near it (file size must be < 100000 bytes).

#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>

void on_destroy (GtkWidget *widget G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED)
{
    gtk_main_quit ();
}

int main (int argc, char *argv[]) 
{
    FILE *f;
    guint8 buffer[100000];
    gsize length;
    GdkPixbufLoader *loader;
    GdkPixbuf *pixbuf;
    GtkWidget *window;
    GtkWidget *image;

    gtk_init (&argc, &argv);

    f = fopen ("test.jpg", "r");
    length = fread (buffer, 1, sizeof(buffer), f);
    fclose (f);

    loader = gdk_pixbuf_loader_new ();
    gdk_pixbuf_loader_write (loader, buffer, length, NULL);
    pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    image = gtk_image_new_from_pixbuf (pixbuf);
    gtk_container_add (GTK_CONTAINER (window), image);
    gtk_widget_show_all (GTK_WIDGET (window));
    g_signal_connect (window, "destroy", G_CALLBACK(on_destroy), NULL);
    gtk_main ();

    return 0;
}

Original Answer:

The char * or unsigned char * here has little importance.

gdk_pixbuf_new_from_data will only read uncompressed RGB data (the only colorspace supported is GDK_COLORSPACE_RGB) with an alpha channel (RGBA) or without it (RGB). No wonder passing it JPEG fails.

Calling gdk_pixbuf_loader_write looks like a better option, but we'd need some code to see what you may doing wrong. Check however that you have the pixbuf loader for jpg installed by running in a shell the gdk-pixbuf-query-loaders command, and verifying that JPEG is there.