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?
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.
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