简体   繁体   English

如何使用GTK3和PyGObject绘制GdkPixbuf

[英]How to draw a GdkPixbuf using GTK3 and PyGObject

I have a small application that uses a DrawingArea to draw a simple map using PyGObject and GTK3 . 我有一个小应用程序,它使用DrawingArea使用PyGObjectGTK3绘制一个简单的地图。

I load a Pixbuf using 我使用加载Pixbuf

from gi.repository import Gtk, GdkPixbuf
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size("logo.png", 25, 25)

and then try to draw it in the DrawingArea 's draw event signal 然后尝试在DrawingArea的绘图事件信号中绘制它

def draw(self, widget, context):
    window = widget.get_window()
    ctx = window.cairo_create()
    ctx.set_source_pixbuf(pixbuf, 0, 0)

but I get the error message 但我收到错误信息

"AttributeError: 'cairo.Context' object has no attribute 'set_source_pixbuf'"

If I'm reading the Gtk2 to Gtk3 migration guide correctly, this should work. 如果我正确地阅读Gtk2到Gtk3迁移指南 ,这应该可行。 What am I doing wrong? 我究竟做错了什么?

The new draw signal uses a callback that already passes the cairo context as a parameter, you don't need to do stuff like window = widget.get_window() like you did in PyGtk to get the cairo context while attending the expose-event signal. 新的绘制信号使用已经将cairo上下文作为参数传递的回调,你不需要像在PyGtk中那样做像window = widget.get_window()这样的东西来获取cairo上下文,同时参加expos -event信号。 In PYGObject is simpler: 在PYGObject中更简单:

import cairo

class Foo(object):
    def __init__(self):

       (...)
        self.image = cairo.ImageSurface.create_from_png('logo.png')
       (...)

    def draw(self, widget, context):
        if self.image is not None:
            context.set_source_surface(self.image, 0.0, 0.0)
            context.paint()
        else:
            print('Invalid image')
        return False

That is if you don't need the PixBuf, but if you need it for something else you have several options: 也就是说,如果您不需要PixBuf,但如果您需要其它的东西,您有几个选择:

  1. To have both objects in memory. 将两个对象都放在内存中。 If both are loaded from a PNG there should not be much problems other than the waste of memory. 如果两者都是从PNG加载的,那么除了浪费内存之外,应该没有太多问题。
  2. Convert GdkPixbuf to PIL Image, then PIL Image to data array and then create a Cairo ImageSurface from that data array using create_for_data(). 将GdkPixbuf转换为PIL Image,然后将PIL Image转换为数据数组,然后使用create_for_data()从该数据数组创建Cairo ImageSurface。 Yak :SI don't know better, sorry :S 牦牛:SI不知道更好,对不起:S
  3. Use Gdk.cairo_set_source_pixbuf() proposed by hock. 使用hock提出的Gdk.cairo_set_source_pixbuf() This seems to be the correct way to draw a Pixbuf in a ImageSurface, but it is totally unpythonic (and that's why I hate this Introspection stuff, all looks like C, like a bad C port). 这似乎是在ImageSurface中绘制Pixbuf的正确方法,但它完全是unpythonic(这就是为什么我讨厌这个Introspection的东西,所有看起来像C,就像一个坏的C端口)。

If you choose the awful second option here is how: 如果你选择了糟糕的第二个选项,那么如何:

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)

Note that create_for_data() is not yet available for Python3 , only for Python2 . 请注意, create_for_data() 尚不适用于Python3仅适用于Python2

Check also my answer on how to use a double buffer in PyGObject if this is what you're trying to achieve: Drawing in PyGobject (python3) 如果这是你想要实现的,请查看我在PyGObject中如何使用双缓冲区的答案: 在PyGobject中绘图(python3)

Kind regards 亲切的问候

The following seems to do the job: 以下似乎做了这个工作:

def draw(self, widget, context):
    Gdk.cairo_set_source_pixbuf(context, self.pixbuf, 0, 0)
    context.paint()

One question still remains: Is this the preferred way of doing things? 一个问题仍然存在:这是首选的做事方式吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM