我有一个需要加载未知大小图像的PyGTK应用程序,但我遇到的问题是,如果图像非常大或非常小,窗口布局会变形并且难以使用。我需要一些方法使图像自动缩放以适合其父窗口小部件。不幸的是,经过一些研究后,似乎没有代码,内置或其他方式,可以完成我正在寻找的东西。
我怎么能写一些东西呢?我原本以为有人会为此编写一些代码;有没有我错过的东西?
答案 0 :(得分:9)
您可以使用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 :(得分: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()
答案 2 :(得分:0)
以下是在绘图区域完成此任务的除外:
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()