PyGTK:如何使图像自动缩放以适应其父部件?

10

我有一个PyGTK应用程序需要加载一个未知大小的图像,但是如果图像非常大或非常小,则窗口布局变得扭曲且难以使用。我需要某种方法使图像自动缩放以适应其父部件。不幸的是,在进行了一些研究后,似乎没有任何内置或其他方式可以做到我所寻找的。

我该如何编写代码来实现这一点?我本以为已经有人写过这样的代码,我错过了什么吗?

3个回答

10
你可以使用 widget.get_allocation() 函数获取父部件的大小,使用 pixbuf.scale_simple 函数缩放图像,如下所示:
allocation = parent_widget.get_allocation()
desired_width = allocation.width
desired_height = allocation.height

pixbuf = gtk.gdk.pixbuf_new_from_file('your_image.png')
pixbuf = pixbuf.scale_simple(desired_width, desired_height, gtk.gdk.INTERP_BILINEAR)
image = gtk.image_new_from_pixbuf(pixbuf)

如果您想让图片在每次调整窗口大小时都按比例缩放,您需要将上述代码(或类似的代码,以避免每次从磁盘加载图像)放入与父部件的size_allocate信号相连的函数中。为避免无限循环,请确保放入小部件的图像不会再次改变其大小。
参考资料:

1
非常有帮助,谢谢。我使用了 image.set_from_pixbuf(pixbuf) 而不是 image = gtk.image_new_from_pixbuf(pixbuf) - Zaz

1
这是一个在绘图区域上完成此任务的示例:
    self.spash_pixbuf = GdkPixbuf.Pixbuf.new_from_file('myfile.png')
    ...

    def on_draw(self, widget, cairo_ct):
        """
            draw
        """
        self._cairo_ct = cairo_ct
        self._width = widget.get_allocated_width()
        self._height = widget.get_allocated_height()

        self._draw_cover(self.spash_pixbuf)

    def _draw_cover(self, pixbuf):
        """
            Paint pixbuf to cover drawingarea.
        """
        img_width = float(pixbuf.get_width())
        img_height = float(pixbuf.get_height())
        # Scale
        width_ratio = self._width / img_width
        height_ratio = self._height / img_height
        scale_xy = max(height_ratio, width_ratio)
        # Center
        off_x = (self._width  - round(img_width*scale_xy)) //2
        off_y = (self._height - round(img_height*scale_xy)) //2

        # Paint
        self._cairo_ct.save()

        self._cairo_ct.translate(off_x, off_y)
        self._cairo_ct.scale(scale_xy, scale_xy)

        Gdk.cairo_set_source_pixbuf(self._cairo_ct, pixbuf, 0, 0)
        self._cairo_ct.paint()

        self._cairo_ct.restore()

0

这里有一些小片段的类,可以让您使用自动缩放图像。

import gtk


class ImageEx(gtk.Image):
    pixbuf = None

    def __init__(self, *args, **kwargs):
        super(ImageEx, self).__init__(*args, **kwargs)
        self.connect("size-allocate", self.on_size_allocate)

    def set_pixbuf(self, pixbuf):
        """
        use this function instead set_from_pixbuf
        it sets additional pixbuf, which allows to implement autoscaling
        """
        self.pixbuf = pixbuf
        self.set_from_pixbuf(pixbuf)

    def on_size_allocate(self, obj, rect):
        # skip if no pixbuf set
        if self.pixbuf is None:
            return

        # calculate proportions for image widget and for image
        k_pixbuf = float(self.pixbuf.props.height) / self.pixbuf.props.width
        k_rect = float(rect.height) / rect.width

        # recalculate new height and width
        if k_pixbuf < k_rect:
            newWidth = rect.width
            newHeight = int(newWidth * k_pixbuf)
        else:
            newHeight = rect.height
            newWidth = int(newHeight / k_pixbuf)

        # get internal image pixbuf and check that it not yet have new sizes
        # that's allow us to avoid endless size_allocate cycle
        base_pixbuf = self.get_pixbuf()
        if base_pixbuf.props.height == newHeight and base_pixbuf.props.width == newWidth:
            return

        # scale image
        base_pixbuf = self.pixbuf.scale_simple(
            newWidth,
            newHeight,
            gtk.gdk.INTERP_BILINEAR
        )

        # set internal image pixbuf to scaled image
        self.set_from_pixbuf(base_pixbuf)

还有一个小的使用示例:

class MainWindow(object):
    def __init__(self):
        self.window = gtk.Window()
        self.window.connect("destroy", gtk.main_quit)

        # create new ImageEx
        self.image = ImageEx()
        # set size request, to limit image size
        self.image.set_size_request(width=400, height=400)
        # load image from file, change path with path of some of your image
        pixbuf = gtk.gdk.pixbuf_new_from_file("path/to/your/image.jpeg")

        # that's the key moment, instead `set_from_pixbuf` function
        # we use our newly created set_pixbuf, which do some additional assignments
        self.image.set_pixbuf(pixbuf)

        # add widget and show window
        self.window.add(self.image)
        self.window.show_all()

if __name__ == '__main__':
    MainWindow()
    gtk.main()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接