我有一个PyGTK应用程序需要加载一个未知大小的图像,但是如果图像非常大或非常小,则窗口布局变得扭曲且难以使用。我需要某种方法使图像自动缩放以适应其父部件。不幸的是,在进行了一些研究后,似乎没有任何内置或其他方式可以做到我所寻找的。
我该如何编写代码来实现这一点?我本以为已经有人写过这样的代码,我错过了什么吗?
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)
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()
这里有一些小片段的类,可以让您使用自动缩放图像。
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()
image.set_from_pixbuf(pixbuf)
而不是image = gtk.image_new_from_pixbuf(pixbuf)
。 - Zaz