Display image with pygobject and python 3 from data in memory

I have some RGBA data in Python 3, and I want to display the image that it represents in the GTK3 window, without using any additional libraries.

The first thing I tried was to edit the Pixbuf data, as in the example (http://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-The-GdkPixbuf-Structure.html#put-pixel - sorry, I am only allowed 2 links) in the documentation (C) using Pixbuf.get_pixels() . This gives me an immutable bytes object, although it obviously won't work. (The gdk-pixbuf bug report (668084, would refer to it if SO let me) covered the same function, but the stuff must have changed a little since then.)

Next, I tried to create a Pixbuf from the data using Pixbuf.new_from_data() , but this is also buggy (see gdk-pixbuf bug 674691) (yes, I comment 3).

Then I looked at Cairo: ImageSurface.create_for_data should do this, but for some reason this is not yet available in Python 3 binding. (I tried this with Python 2, after that turning the surface into Pixbuf and then wrapping it in gtk.Image and it works. But I use Python3 (and even then, this is messy. Cairo is a vector graphics library, after all)).

I found a link somewhere to use PIL to write an image to a PNG file and then read it in Pixbuf, but it's awful, it uses an extra library, and PIL is not yet available for Python 3.

So ... any other methods?

Working code

Based on Havok's answer, here is a working example:

 from array import array from gi.repository import Gtk as gtk, GdkPixbuf pixels = array('H') for i in range(20): for j in range(20): px = (i < 10, j >= 10, (i < 10) ^ (j < 10)) pixels.extend(65535 * c for c in px) header = b'P6 20 20 65535 ' img_data = header + pixels w = gtk.Window() w.connect('delete-event', gtk.main_quit) l = GdkPixbuf.PixbufLoader.new_with_type('pnm') l.write(img_data) w.add(gtk.Image.new_from_pixbuf(l.get_pixbuf())) l.close() w.show_all() gtk.main() 

Edit: in fact, for the pixels.byteswap() correctness, I think that to add to the header you will need pixels.byteswap() for small systems (although, of course, it does not matter with these colors).

+7
source share
2 answers

Wow, that will be tricky, pretty tricky.

Neither PIL nor Cairo ImageSurface.create_from_data () are available for Python 3. It remains only to use GdkPixbuf, but, as you said, this is not an ideal solution, in particular because you expect to use the alpha channel, My only thought is that you are trying to use this:

http://developer.gnome.org/gdk-pixbuf/stable/GdkPixbufLoader.html#gdk-pixbuf-loader-new-with-type

As I did at the end: Pil Conversion GdkPixbuf

 loader = GdkPixbuf.PixbufLoader.new_with_type('pnm') loader.write(contents) pixbuf = loader.get_pixbuf() loader.close() 

And try to see what types are supported, the PyGObject version could not be found, as the C documentation says about gdk_pixbuf_format_get_name() and gdk_pixbuf_get_formats() . With pnm format , you will not have an alpha channel.

EDIT

Well, you found the PyGObject functions by posting the output here for documentation purposes:

 >>> from gi.repository import GdkPixbuf >>> formats = GdkPixbuf.Pixbuf.get_formats() >>> [f.get_name() for f in formats] ['GdkPixdata', 'ras', 'tiff', 'wmf', 'icns', 'ico', 'png', 'qtif', 'wbmp', 'gif', 'pnm', 'tga', 'ani', 'xbm', 'xpm', 'jpeg2000', 'pcx', 'jpeg', 'bmp', 'svg'] 
+4
source

I don't have gtk3, but in gtk2 it worked fine:

 import gtk import cairo def main(): window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_title("Drawing Area") window.connect("destroy", lambda w:gtk.main_quit()) sw = gtk.ScrolledWindow() area = Area() area.show() area.connect('expose-event', area.expose_handler) sw.add_with_viewport(area) window.add(sw) window.show_all() class Area(gtk.DrawingArea): def __init__(self): super(Area, self).__init__() self.pixbuf = gtk.gdk.pixbuf_new_from_file("hard_drive_elements.png") def expose_handler(self, widget, event): cr = self.window.cairo_create() cr.set_operator(cairo.OPERATOR_SOURCE) cr.set_source_rgb(1,1,1) cr.paint() cr.set_source_pixbuf(self.pixbuf, 0, 0) cr.paint() if __name__ == "__main__": main() gtk.main() 

Drawing_area_from_pixbuf

+2
source

All Articles