Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic image scaling on resize with (Py)GTK

Tags:

python

pygtk

gtk

I have a GtkImage widget in a resizable window and a reference GdkPixBuf storing the image I want to fill the GtkImage with.

I can scale the GdkPixBuf to fill the GtkImage widget using this method:

def update_image(self, widget=None, data=None):
    # Get the size of the source pixmap
    src_width, src_height = self.current_image.get_width(), self.current_image.get_height()

    # Get the size of the widget area
    widget = self.builder.get_object('image')
    allocation = widget.get_allocation()
    dst_width, dst_height = allocation.width, allocation.height

    # Scale preserving ratio
    scale = min(float(dst_width)/src_width, float(dst_height)/src_height)
    new_width = int(scale*src_width)
    new_height = int(scale*src_height)
    pixbuf = self.current_image.scale_simple(new_width, new_height, gtk.gdk.INTERP_BILINEAR)

    # Put the generated pixbuf in the GtkImage widget
    widget.set_from_pixbuf(pixbuf)

When I call update_image manually it works as expected. Now I want the scaling to occur automatically when the GtkImage widget is resized. The best solution I came with was to bind the update_image method to the configure-event GTK event of the window. After each size change of the window, the image is indeed properly scaled. However I have two issues with this solution:

  • I can only make the window bigger. Once the image has been upscaled, GTK won't let me resize the window smaller because the window can't be smaller than its widgets. I understand why it works like that but I don't know how to change this behaviour.
  • Maybe this is no big deal but I would have preferred an event from the GtkImage widget instead of the top-level window.

I am sorry for the long explanation of such a trivial problem, I hope you'll be able to help me.

like image 346
Jim Avatar asked Feb 08 '11 23:02

Jim


1 Answers

I believe you could use expose-event signal of the widget for image scaling. Also adding image into scrollable container should fix the problem with window resize. Please check if an example below would work for you.

import gtk

class ScaleImage:
    def __init__(self):
        self.temp_height = 0
        self.temp_width = 0

        window = gtk.Window(gtk.WINDOW_TOPLEVEL)

        image = gtk.Image()
        image.set_from_file('/home/my_test_image.jpg')
        self.pixbuf = image.get_pixbuf()
        image.connect('expose-event', self.on_image_resize, window)    

        box = gtk.ScrolledWindow()
        box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        box.add(image)

        window.add(box)
        window.set_size_request(300, 300)
        window.show_all()        

    def on_image_resize(self, widget, event, window):
        allocation = widget.get_allocation()
        if self.temp_height != allocation.height or self.temp_width != allocation.width:
            self.temp_height = allocation.height
            self.temp_width = allocation.width
            pixbuf = self.pixbuf.scale_simple(allocation.width, allocation.height, gtk.gdk.INTERP_BILINEAR)
            widget.set_from_pixbuf(pixbuf)

    def close_application(self, widget, event, data=None):
        gtk.main_quit()
        return False

if __name__ == "__main__":
    ScaleImage()
    gtk.main()

hope this helps, regards

like image 167
serge_gubenko Avatar answered Nov 15 '22 08:11

serge_gubenko