12

我在 Python 3 中有一些 RGBA 数据,我想在 GTK3 窗口中显示它所代表的图像,而不使用任何额外的库。

我尝试的第一件事是编辑 aPixbuf的数据,例如(http://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-The-GdkPixbuf-Structure.html#put-pixel - 抱歉,我'm only allowed 2 links) in the (C) documentation, using Pixbuf.get_pixels(). 但是,这给了我一个不可变的bytes对象,因此显然行不通。(一个 gdk-pixbuf 错误报告(668084,如果允许我会链接到它)涵盖了相同的功能,但从那以后东西必须有所改变。)

接下来,我尝试使用从数据创建 Pixbuf Pixbuf.new_from_data(),但这也有问题(请参阅 gdk-pixbuf 错误 674691)(是的,这就是我在评论 3 中)。

然后我查看了 Cairo: ImageSurface.create_for_datashould do this,但由于某种原因,这在 Python 3 绑定中尚不可用。(我已经用 Python 2 尝试过,然后将表面变成 a Pixbuf,然后将其包装在 agtk.Image中,它可以工作。但我使用的是 Python3(即使这样,它也很混乱 - 毕竟 Cairo 是一个矢量图形库) )。

我在某处找到了使用 PIL 将图像写入 PNG 文件然后将其读入 Pixbuf 的参考,但这太可怕了,使用了一个额外的库,而且 PIL 无论如何都不适用于 Python 3。

那么……还有其他方法吗?

工作代码

根据 Havok 的回答,这是一个工作示例:

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()

编辑:实际上,为了正确起见,我认为在添加到标题之前需要一个pixels.byteswap()小端系统(尽管这些颜色当然无关紧要)。

4

3 回答 3

6

哇,这将是一个艰难的,非常困难的。

PIL 或 Cairo 的 ImageSurface.create_from_data() 都不适用于 Python 3。您唯一的选择是直接使用 GdkPixbuf,但正如您所说,这不是一个完美的解决方案,特别是因为您希望使用 alpha 通道。我唯一的想法是你尝试使用这个:

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

正如我在此处末尾所做的那样:Converting PIL GdkPixbuf

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

并尝试查看支持哪些类型,找不到 C 文档所说的 PyGObject 版本gdk_pixbuf_format_get_name()gdk_pixbuf_get_formats(). 使用pnm 格式,您将没有 alpha 通道。

编辑

太好了,您找到了 PyGObject 函数,在此处发布输出以用于文档目的:

>>> 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']
于 2012-09-15T07:13:49.507 回答
3

我没有安装 gtk3,但在 gtk2 中它工作得非常好:

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

于 2012-09-14T19:28:59.280 回答
0

这现在适用于 Python 3:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf

pixels = open('test.raw', 'rb').read()
depth = 8
width = 460
height = 460
stride = width * 3
win = Gtk.Window()
win.connect('delete-event', Gtk.main_quit)
win.add(Gtk.Image.new_from_pixbuf(
    GdkPixbuf.Pixbuf.new_from_data(pixels, GdkPixbuf.Colorspace.RGB,
                                   False, depth, width, height, stride)))
win.show_all()
Gtk.main()

您可以.raw使用 ImageMagick 从 JPEG 或其他常见图像格式创建图像:

convert test.jpeg -depth 8 -size 460x460 RGB:test.raw

我没有检查是否可以加载 alpha 通道(透明度)数据,但new_from_data()需要一个布尔标志。

于 2018-04-04T21:27:21.170 回答