4

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!

Matekk
  • 683
  • 2
  • 8
  • 21

1 Answers1

10

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);
    gdk_pixbuf_loader_close(loader, 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.

chappjc
  • 30,359
  • 6
  • 75
  • 132
liberforce
  • 11,189
  • 37
  • 48
  • I ran `gdk-pixbuf-query-loaders` and JPEG is installed. Also, I will edit the question to include some code. – Matekk Jan 02 '13 at 14:36
  • 1
    Why not use gdk_pixbuf_new_from_stream with a GMemoryInputStream? – ergosys Jan 02 '13 at 23:15
  • Unfortunately, I get "Unrecognized image file format". And again, if I just write that same data stream into a file it results in a properly working .jpg image. – Matekk Jan 03 '13 at 08:47
  • I suspect you might need to only pass the pixel buffer, not the file header. Just an idea. Looking at the source code for [`gdk_pixbuf_new_from_file`](http://git.gnome.org/browse/gdk-pixbuf/tree/gdk-pixbuf/gdk-pixbuf-io.c#n1057) to see how it loads the file may help. – liberforce Jan 03 '13 at 11:55
  • 1
    Ok, just got it. Using gdk_pixbuf_loader_write on the full buffer works perfectly fine. Your problem is that your "stride" parameter is not in the prototype. Removing it works for me. – liberforce Jan 03 '13 at 13:23
  • Ugh, actually, that was a misprint, sorry :( still unrecognized image format – Matekk Jan 03 '13 at 13:57
  • 1
    I added my working sample app. Add some error checking if it doesn't work with your image, as it may be a problem specific to that image. – liberforce Jan 03 '13 at 14:15
  • Funny, if I open the .jpg file, and use the char* stream i read from that, the pixbuf_loader fails with a message: Error interpreting JPEG image file (Bogus Huffman table definition) – Matekk Jan 03 '13 at 14:17
  • Your example indeed works with my image! I'll examine it a bit more, thank you! – Matekk Jan 03 '13 at 14:26
  • It works, the error in my code was one function i called before loader write that changed my cast back to const char* :S Thanks! – Matekk Jan 03 '13 at 18:45
  • As I said, the cast has little to do here. Even without it, there would have been an implicit cast. My guess is that this function call corrupted the buffer. – liberforce Jan 04 '13 at 10:49
  • 1
    For me this worked only after I added a gdk_pixbuf_loader_close call before the gdk_pixbuf_loader_get_pixbuf call. – Didi Kohen Nov 27 '14 at 10:12