How to auto resize images according to window size

Hello. I’m trying to create a image gallery type of program for learning GTK3.

I’m using GTK3 library but I can’t figure out how to make the images auto scale themselves when I resize the window.

I’m using this layout:
GTKWindow → GTK Box → GTK Grid → [] GTK Image

How can I accomplish it? :slight_smile:

Have you already asked Google? I think one solution is using GtkPixbuf, see Python GTK resizing large image to fit inside a window - Stack Overflow That is still for GTK3, but it seems that you do not intent to use GTK4 at all, and it may work similar for GTK4.

I’m using gotk3 GTK3 wrapper for GTK3. So yes I’m using GTK3.

I have asked Google actually :sweat_smile: I’m trying to resize it dynamically according to image box size. Google suggests using Gtk.DrawingArea instead of Gtk.Image and hooking it’s draw signal.

I can’t figure out which signal event to hook for Gtk.Image and how to handle the resize without freezing the main thread.

Also where do I keep the pixbuf everytime I resize?

I can not really help you, as I have not used GtkImage before myself, so we have to wait for other people or for Mr. Bassi again :slight_smile:

You start learning GTK with a not that easy task. As you are using GoLang: How good are the Go GTK bindings, and does Go not support GTK4? If my memory is correct, Go has developed its own GUI toolkit, can not remember the name, something like libui? Some people suggested using that Go lib for Nim some years ago, but I have never heard about it again. So I am still struggling with my gintro GTK bindings.

Well, here is one more C example:

Not Go but only plain C, but maybe it is a starting point for you.

Don’t worry. I can read c, c++, python3, c#, rust, go, nim, java. I’m trying to do hard tasks to try learn more stuff by solving problems rather than walking a paved path. I learn fast this way (like goku lol) :slight_smile:

Yes I’ve seen c and c++ (gtkmm) implementations, but I find it somewhere lacking. Everyone suggest using drawing areas where’s there’s draw signal in Gtk.Image too.

I know about golang’s cross platform ui, but I want to learn something new. I’m trying out GTK3 for fun.

Ah. This looks interesting, thanks. I’ll definitely try this and reply.

Ok, that accepted stackoverflow answer is the worst thing I’ve ever seen in my life.

The actual thing you need to do is to just write your own widget.

  1. Subclass GtkWidget (or GtkDrawingArea I guess)
  2. In your widget subclass, have some setter for the image. Preferrable always work with cairo_surface_t as that is what is being drawn in the end anyway. If you save your images as GdkPixbuf or anything else, convert them to a cairo_surface_t
  3. Override ::draw
    3.5) There is a function called gdk_cairo_set_source_pixbuf() that people love to use here. Instead of working with a cairo_surface_t, it takes a GdkPixbuf which is more common. You can do that too, but the function does nothing but convert the pixbuf to a surface and then set that as the source surface. In other words, it’s slow.
  4. In ::draw, you can use simple cairo commands to draw your surface, and scale it using cairo_scale(). Get the size of the widget, the size of the surace, do a bit of math and voila.

DO NOT connect to size-allocate and resize a pixbuf or some garbage. That’s just hilarious.

2 Likes

thanks a lot for mentioning that. i was trying it with size-allocate just about now.

also, whats a faster implementation? i don’t mind using it even if its lenthy, performance matters to me.

also in golang and c/c++ where do i store the full res cairo every time i resize? do i just make it global or can i assign a custom variable to the custom widget somehow (like python has self for its classes)?

What I listed is much faster. You only run into problems once your image is too big for cairo to perfomantly scale once per frame.

You are writing a new class anyway, just make it a class variable.

What I listed is much faster. You only run into problems once your image is too big for cairo to perfomantly scale once per frame.

Um, I’m trying to load images from reddit after this. I think this would give me problems lol.

Do you think the generalized version (gdk_cairo_set_source_pixbuf()) would be better for loading images from internet?

You are writing a new class anyway, just make it a class variable.

Yeah. i was thinking the same. Problem is golang doesn’t have classes, but i think that’d be off-topic for this. I’ll find a way :stuck_out_tongue:

What does “load images from reddit” mean? That you’re downloading images during draw or size-allocate? Because that’s inherently broken.

You can load an image at any random point, and save it locally in a cache directory; then load the image data from disk and store it into a Cairo image surface and queue a redraw on the widget that will display the image.

I’ll make http requests when user press a button, then parse the json for preview images, then http request to get those images and store them into pixbufs (from raw http bytes).

(http endoint: https://api.reddit.com/r/pics/.json)

After that i want to somehow auto scale the images to fit a Flow Box. Like a vertical image gallery.

You said you wanted to scale it to “window size” so I assumed something like a image viewer use case.

If you only scale using cairo, you of course have to consider that the larger image stays in RAM even though you only draw a tiny thumbnail of it.

I’m sorry, I went a little offtopic there. I think it’d be better to create a new post for a different project.

Yes the solution you both suggested worked incredibly well. I haven’t noticed flickering but a little memory usage.

I assume that’s because the older pixbuf stays in memory. Pretty sure if I load multiple images it would cause memory leak in no time.

Anyway I’ll make a new post for that. This topic has been solved :slight_smile:

Thanks everyone :smiley: