PyGTK:如何使图像自动缩放以适合其父窗口小部件?

发布于 2024-10-18 07:35:30 字数 183 浏览 3 评论 0原文

我有一个 PyGTK 应用程序需要加载未知大小的图像,但是我遇到的问题是,如果图像非常大或非常小,窗口布局会变得扭曲并且难以使用。我需要某种方法使图像自动缩放以适合其父窗口小部件。不幸的是,经过一些研究后,似乎没有内置或其他代码可以满足我的要求。

我怎样才能写一些东西来做到这一点?我本以为有人已经为此编写了一些代码;有什么我错过的吗?

I have a PyGTK app that needs to load an image of unknown size, however I am having the problem that if the image is either very big or very small, the window layout becomes distorted and hard to use. I need some way of making the image automatically scale to fit its parent widget. Unfortunately, after doing some research, it seems there is no code, built in or otherwise, that does what I'm looking for.

How could I go about writing something to do this? I would have thought that somebody would have written some code for this already; is there something that I missed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

留一抹残留的笑 2024-10-25 07:35:30

您可以使用 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 信号的函数中。为了避免无限循环,请确保放入小部件中的图像不会再次改变其大小。

参考文献:

You can use widget.get_allocation() to find out the size of the parent widget and pixbuf.scale_simple to scale the image, like this:

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)

If you want the image to scale each time the window is resized, you'll have to put the code above (or something similar, to avoid loading the image from disk every time) in a function connected to the size_allocate signal of the parent widget. To avoid infinite loops, make sure that the image you put in the widget doesn't alter its size again.

References:

弥繁 2024-10-25 07:35:30

下面是在绘图区域完成此任务的一个例外:

    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()

Here is an except that accomplishes this task on a drawing area:

    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()
笔芯 2024-10-25 07:35:30

这里有一些小片段类,允许您使用自动缩放图像。

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()

Here some small snippet class which allows you to use auto scaled image.

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)

And small usage example:

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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文