Reputation: 2653
I'm downloading an image from a web page, the image is too big (600px largest edge normally), and I want to scale it down to fit in a 220x220px box.
The code as I have it works - except for the final size. The image is downloaded, and then put in the GtkImage (it's from a Glade layout). I'm downloading it into a temporary file as I can't seem to directly transfer the data from the web site into the image. Now the problem is this image is way too big when displayed in the application.
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()
On a side note, I'd love to get rid of that temporary file construction :)
Please note, I'm using GTK3.
Upvotes: 2
Views: 4855
Reputation: 1116
Use Gdk.Pixbuf.new_from_file_at_scale() along with 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)
If you want to preserve the aspect, just set that argument to True or use: GdkPixbuf.Pixbuf.new_from_file_at_size(f.name, width=220, height=220)
Side note: The reason you need to call read() before using the file is because it is buffered and hasn't been written to disk. The read call is causing the buffer to flush, a clearer technique (from a readability standpoint) would be to call flush() instead of read().
If you want to get rid of the temporary file, use the Gio module along with a streaming 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)
You can take things further by using an async image stream which then injects the completed results into the app when the pixbuf is ready, maintaining interactivity in the UI during the file transfer:
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
Note we cannot use the nice keyword arguments in the async version because of the user_data arg. This goes away in pygobject 3.12 where the user_data can actually be left off if not used (or used as a keyword arg too).
Upvotes: 4
Reputation: 28553
Use pixbuf (part of gtk)
def scale(dest, dest_x, dest_y, dest_width, dest_height, offset_x, offset_y, scale_x, scale_y, interp_type)
or for simple scale
gtk.gdk.Pixbuf.scale_simple
def scale_simple(dest_width, dest_height, interp_type)
You can still use Pixbuf in gtk3 by importing the gdk but you need to import 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)
Upvotes: 0