pyGtk: Image prevents window resize
Question: So I am attempting to make a GTK application using python, and I have run into
this issue where after I place an image on a window, I can increase the size
of the window, but not decrease it. Given that the purpose of this particular
window is to display a resizable image, this is rather bothersome.

I have extracted the relevant code which demonstrates this behavior below

    
    
    #!/usr/bin/env python
    from gi.repository import Gtk, GdkPixbuf
    import sys
    
    class ImageWindow(Gtk.Window):
        def __init__(self, image_data):
            Gtk.Window.__init__(self, title="image test")
            if image_data and len(image_data) > 0:
                self.loader = GdkPixbuf.PixbufLoader()
                self.loader.write(image_data)
                self.pixbuf = self.loader.get_pixbuf()
                self.image = Gtk.Image.new_from_pixbuf(self.pixbuf)
            else:
                self.image = Gtk.Image.new()
            self.add(self.image)
            self.connect('delete-event', Gtk.main_quit)
    
    win = ImageWindow(sys.stdin.read())
    win.show_all()
    Gtk.main()
    

If you pipe in nothing, the window resizes fine. Pipe in an image, and the
form clicks to the size of the image, and can resize bigger, but cannot resize
smaller.


Answer: So here is an example of a scaling image. The idea is that you put the image
in a Gtk.ScrolledWindow() and resize the image as soon as the window is
resized.:

    
    
    #!/usr/bin/env python
    from gi.repository import Gtk, GdkPixbuf, GLib
    import sys
    
    class ImageWindow(Gtk.Window):
        def __init__(self, image_data):
            Gtk.Window.__init__(self, title="image test")
            self.connect('delete-event', Gtk.main_quit)
    
            self.image = Gtk.Image()
            scrolled_window = Gtk.ScrolledWindow()
            scrolled_window.add(self.image)
            self.add(scrolled_window)
    
            if len(image_data) == 0:
                return
    
            self.loader = GdkPixbuf.PixbufLoader()
            self.loader.write(image_data)
            self.loader.close()
            self.pixbuf = self.loader.get_pixbuf()
            self.image.set_from_pixbuf(self.pixbuf)
    
            width = self.pixbuf.get_width()
            height = self.pixbuf.get_height()
            self.dimension = float(width) / height
            self.set_default_size(width, height)
            self.connect('check-resize', self.on_resize)
    
        def on_resize(self, window):
            width, height = self.get_size()
            if float(width) / height > self.dimension:
                self.pixbuf = self.pixbuf.scale_simple(
                    self.dimension * height,
                    height,
                    GdkPixbuf.InterpType.NEAREST
                )
            else:
                self.pixbuf = self.pixbuf.scale_simple(
                    width,
                    width / self.dimension,
                    GdkPixbuf.InterpType.NEAREST
                )
            GLib.idle_add(self.image.set_from_pixbuf, self.pixbuf)
    
    win = ImageWindow(sys.stdin.read())
    win.show_all()
    Gtk.main()
    

As an alternative, you can load the pixbuf again from the loader and scale it
afterwards. This looks better if you make your image smaller and then larger
again but needs more processing:

    
    
    def on_resize(self, window):
        width, height = self.get_size()
        self.pixbuf = self.loader.get_pixbuf()
        if float(width) / height > self.dimension:
            self.pixbuf = self.pixbuf.scale_simple(
                self.dimension * height,
                height,
                GdkPixbuf.InterpType.BILINEAR
            )
        else:
            self.pixbuf = self.pixbuf.scale_simple(
                width,
                width / self.dimension,
                GdkPixbuf.InterpType.BILINEAR
            )
        GLib.idle_add(self.image.set_from_pixbuf, self.pixbuf)
    

