I'm trying to find an example of showing an image in GTK 4.0 from an existing memory buffer, where the image is stored in the form of an array of floats of size width x height x 3. I understand I need to use GtkImage, but I don't know how to pass such an array to it.
Just for context, I wanted to implement a prototype for rendering some images, they are all rendered in memory, and as a result, I have an array of such floats, three floats for each pixel. Unfortunately, I could not find any examples for the latest GTK 4.0. There are plenty of examples of loading an image from the disk, but it seems like jumping unnecessary hoops for my case. I used to load these as OpenGL texture and show them on a quad, but it also seems like driving nails with a sledgehammer.
Thank you in advance for any help!
You can use GdkMemoryTexture
for an image in memory and use a GtkPicture
and set the texture using gtk_picture_set_paintable()
to paint it. The following is an example that creates an opaque 8bit RGB image and displays it on the screen:
/* pixel.c
*
* Compile: cc -ggdb pixel.c -o pixel $(pkg-config --cflags --libs gtk4) -o pixel
* Run: ./pixel
*
* Author: Mohammed Sadiq <www.sadiqpk.org>
*
* SPDX-License-Identifier: LGPL-2.1-or-later OR CC0-1.0
*/
#include <gtk/gtk.h>
#define BYTES_PER_R8G8B8 3
#define WIDTH 400
static void
fill_row (GByteArray *array,
guint8 value,
int row_size)
{
guint i;
for (i = 0; i < row_size; i++) {
/* Fill the same values for RGB */
g_byte_array_append (array, &value, 1); /* R */
g_byte_array_append (array, &value, 1); /* G */
g_byte_array_append (array, &value, 1); /* B */
}
}
static void
add_pixel_picture (GtkPicture *picture)
{
g_autoptr(GBytes) bytes = NULL;
GdkTexture *texture;
GByteArray *pixels;
gsize height;
/* Draw something interesting */
pixels = g_byte_array_new ();
for (guint i = 0; i <= 0xff ; i++)
fill_row (pixels, i, WIDTH);
for (guint i = 0; i <= 0xff; i++)
fill_row (pixels, 0xff - i, WIDTH);
height = pixels->len / (WIDTH * BYTES_PER_R8G8B8);
bytes = g_byte_array_free_to_bytes (pixels);
texture = gdk_memory_texture_new (WIDTH, height,
GDK_MEMORY_R8G8B8,
bytes,
WIDTH * BYTES_PER_R8G8B8);
gtk_picture_set_paintable (picture, GDK_PAINTABLE (texture));
}
static void
app_activated_cb (GtkApplication *app)
{
GtkWindow *window;
GtkWidget *picture;
window = GTK_WINDOW (gtk_application_window_new (app));
g_object_set (window,
"width-request", 500,
"height-request", 400,
NULL);
picture = gtk_picture_new ();
gtk_widget_add_css_class (picture, "frame");
g_object_set (picture,
"margin-start", 96,
"margin-end", 96,
"margin-top", 96,
"margin-bottom", 96,
NULL);
gtk_window_set_child (window, picture);
add_pixel_picture (GTK_PICTURE (picture));
gtk_window_present (window);
}
int
main (int argc,
char *argv[])
{
g_autoptr(GtkApplication) app = gtk_application_new (NULL, 0);
g_signal_connect (app, "activate", G_CALLBACK (app_activated_cb), NULL);
return g_application_run (G_APPLICATION (app), argc, argv);
}
Use the GdkMemoryFormat
that suites your data, or convert it to one that's supported.