如何设置GtkImage的大小

2 投票
2 回答
4572 浏览
提问于 2025-04-18 11:13

我正在从网页上下载一张图片,这张图片太大了(通常最大边是600像素),我想把它缩小到适合一个220x220像素的框里。

我现在的代码是可以工作的——除了最后的尺寸不对。图片下载后,会放到GtkImage里(这是从Glade布局中来的)。我把它下载到一个临时文件,因为我似乎无法直接把网站上的数据转到图片里。现在的问题是,这张图片在应用程序中显示时太大了。

f = tempfile.NamedTemporaryFile()
try:
    res = urllib2.urlopen('http://hikingtours.hk/images/meetingpoint_%s.jpg'% (self.tours[tourid]['id'], ))
    f.write(res.read())

    # This f.read() call is necassary, without it, the image
    # can not be set properly.
    f.read()
    self.edit_tour_meetingpoint_image.set_from_file(f.name)
    self.edit_tour_meetingpoint_image.show()

except:
    raise

f.close()

顺便说一下,我希望能去掉那个临时文件的步骤 :)

请注意,我使用的是GTK3。

2 个回答

0

使用 pixbuf(这是gtk的一部分)

def scale(dest, dest_x, dest_y, dest_width, dest_height, offset_x, offset_y, scale_x, scale_y, interp_type)

或者可以使用简单的缩放

gtk.gdk.Pixbuf.scale_simple

def scale_simple(dest_width, dest_height, interp_type)

在gtk3中你仍然可以使用Pixbuf,只需要导入gdk,但还需要导入cairo

import cairo
import Image
import array
from gi.repository import Gtk, GdkPixbuf

width = 25
height = 25
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('logo.png', width, height)
pil_image = Image.fromstring('RGBA', (width, height), pixbuf.get_pixels())
byte_array = array.array('B', pil_image.tostring())
cairo_surface = cairo.ImageSurface.create_for_data(byte_array, cairo.FORMAT_ARGB32, width, height, width * 4)

代码示例参考

4

使用 Gdk.Pixbuf.new_from_file_at_scale() 和 Gtk.Image.set_from_pixbuf() 来处理图片:

pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(f.name, width=220, height=220,
                                                 preserve_aspect_ratio=False)
self.edit_tour_meetingpoint_image.set_from_pixbuf(pixbuf)

如果你想保持图片的比例,只需把那个参数设置为 True,或者使用:GdkPixbuf.Pixbuf.new_from_file_at_size(f.name, width=220, height=220)。

顺便提一下,之所以在使用文件之前需要调用 read(),是因为文件是缓冲的,还没有写入到磁盘。调用 read() 是为了清空缓冲区,从可读性的角度来看,调用 flush() 会更清晰。

如果你想删除临时文件,可以使用 Gio 模块和流式 pixbuf:

from gi.repository import Gtk, GdkPixbuf, Gio

file = Gio.File.new_for_uri('http://www.gnome.org/wp-content/themes/gnome-grass/images/gnome-logo.png')
pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(file.read(cancellable=None),
                                                   width=220, height=220,
                                                   preserve_aspect_ratio=False,
                                                   cancellable=None)
self.edit_tour_meetingpoint_image.set_from_pixbuf(pixbuf)

你还可以进一步使用异步图片流,这样在 pixbuf 准备好时,会将完成的结果注入到应用程序中,同时在文件传输期间保持用户界面的互动性:

from gi.repository import Gtk, GdkPixbuf, Gio

# standin image until our remote image is loaded, this can also be set in Glade
image = Gtk.Image.new_from_icon_name('image-missing', Gtk.IconSize.DIALOG)

def on_image_loaded(source, async_res, user_data):
    pixbuf = GdkPixbuf.Pixbuf.new_from_stream_finish(async_res)
    image.set_from_pixbuf(pixbuf)

file = Gio.File.new_for_uri('http://www.gnome.org/wp-content/themes/gnome-grass/images/gnome-logo.png')
GdkPixbuf.Pixbuf.new_from_stream_at_scale_async(file.read(cancellable=None),
                                                220, 220, # width and height
                                                False,    # preserve_aspect_ratio
                                                None,     # cancellable
                                                on_image_loaded, # callback,
                                                None)     # user_data

注意,在异步版本中,我们不能使用那些好看的关键字参数,因为有一个 user_data 参数。如果在 pygobject 3.12 中,user_data 如果不使用可以省略(或者也可以作为关键字参数使用)。

撰写回答