Displaying an image from a matrix using Gtk4

I want to display an image using Gtk, and be able to change the pixels later. I love ImageView and Makie, but I’m trying to do something as simple and low-level as possibel.

There are a couple of examples in the forum using Gtk (3):

I was trying to use Gtk4, but apparently there have been changes in how you’re suppose to do that. Would anyone have and up-to-date example?

1 Like

Here’s an updated version of the second example:

using Gtk4, Gtk4.GdkPixbufLib

function rgb_to_pixbuf(img_rgb::Array{UInt32})
    (x, y) = size(img_rgb)[1:2]
    data = Array{GdkPixbufLib.RGB}(undef, x, y)
    for i in 1:x, j in 1:y
        data[i, j] = GdkPixbufLib.RGB((img_rgb[i, j, 1]),
                                      (img_rgb[i, j, 2]),
                                      (img_rgb[i, j, 3]))
    end
    GdkPixbuf(data)
end

# creating a red test array
img_rgb = Array{UInt32}(undef, 300, 300, 3)
img_rgb[:,:,1] .= 255
img_rgb[:,:,2] .= 0
img_rgb[:,:,3] .= 0


win = GtkWindow("Matrix", 900, 700) 
pb = rgb_to_pixbuf(img_rgb)
pic = GtkPicture(pb)
win[] = pic

To change the image, you can alter the matrix, create a new pixbuf, then call Gtk4.pixbuf(pic, pb). There might be a way to alter the pixbuf data directly, but this should work.

1 Like

Thanks a lot! I am interested indeed in altering the pixbuf directly, I’m concerned about minimizing memory allocations and copying… Would there be a Gtk based safe way to do it, or maybe we need to define a view using the Pixbuf attributes?

It turns out you can just modify the pixbuf data in place. The code below updates the image without allocating (in Julia):

using Gtk4, Gtk4.GdkPixbufLib

module MatrixFiller
    using Gtk4.GdkPixbufLib
    function incr_green!(pb_rgb)
        for j in eachindex(pb_rgb)
            pb_rgb[j] = GdkPixbufLib.RGB(pb_rgb[j].r,pb_rgb[j].g+32,pb_rgb[j].b)
        end
    end
end

function rgb_to_pixbufrgb(img_rgb::Array{UInt32})
    (x, y) = size(img_rgb)[1:2]
    data = Array{GdkPixbufLib.RGB}(undef, x, y)
    for i in 1:x, j in 1:y
        data[i, j] = GdkPixbufLib.RGB((img_rgb[i, j, 1]),
                                      (img_rgb[i, j, 2]),
                                      (img_rgb[i, j, 3]))
    end
    data
end

# creating a red test array
img_rgb = Array{UInt32}(undef, 300, 300, 3)
img_rgb[:,:,1] .= 255
img_rgb[:,:,2] .= 0
img_rgb[:,:,3] .= 0

win = GtkWindow("Matrix", 900, 700) 
const pb_rgb = rgb_to_pixbufrgb(img_rgb)
const pb = GdkPixbuf(pb_rgb) # this pixbuf uses `pb_rgb` as its data
pic = GtkPicture(pb)
win[] = pic

MatrixFiller.incr_green!(pb_rgb)  # increment the green channel -- no allocations after first call
Gtk4.pixbuf(pic,pb)  # refresh the picture -- no allocations after first call
1 Like

I am trying to do something similar with matrices that look something like this

img = rand(UInt8, 256, 256)

Can you please point me in the right direction?

Have you tried with RGB first?.. Not sure there will be a simple way using grayscale, it must become RGB at some point so the data goes to the monitor

1 Like