更改GdkPixbuf(GTK3)中的像素颜色

时间:2014-11-03 11:42:04

标签: python gtk gtk3 pygobject gdkpixbuf

我正在使用Gtk.StatusIcon,想要更改某些像素的颜色;我有一段工作代码,它会加载一个1x1像素的PNG文件,其中包含我想要设置的颜色,然后将其复制到图标Pixbuf。
虽然这有效,但它有一个明显的缺点,就是必须为每种颜色创建1x1像素,所以我不能使用任意颜色,只能使用我为其创建图像的预定义颜色。

如何将像素设置为任意RGBA颜色?

我现在使用的代码(为演示目的而简化):

#!/usr/bin/env python

from gi.repository import Gtk, GLib, GdkPixbuf

def set_icon_cb(widget, data=None):
    set_icon(widget)

def set_icon(icon):
    fill_amount = 20
    img = GdkPixbuf.Pixbuf.new_from_file('./data/icons/battery.png')
    fill = GdkPixbuf.Pixbuf.new_from_file('./data/icons/green.png')

    for row_num, row in enumerate(zip(*(iter(img.get_pixels()),) *img.get_rowstride())):
        # Blank row
        if 255 not in row: continue

        for col_num, pixel in enumerate(zip(*(iter(row),) * 4)):
            r, g, b, a = pixel

            if col_num > 2 and col_num <= fill_amount and a == 0:
                fill.copy_area(0, 0, 1, 1, img, col_num, row_num)

    icon.set_from_pixbuf(img)


icon = Gtk.StatusIcon()
icon.connect('activate', set_icon_cb)
set_icon(icon)

Gtk.main()

我尝试使用GdkPixbuf.PixbufLoader创建一个新的Pixbuf对象,但这似乎需要一个PNG图像,而不是一个字节对象,所以这不是很有帮助:

fill = GdkPixbuf.PixbufLoader()
fill.write(b'\x88\x88\x88\xff')
fill.close()
fill = fill.get_pixbuf()

# Gives error:
# GLib.Error: gdk-pixbuf-error-quark: Unrecognized image file format (3)

我的下一次尝试是使用GdkPixbuf.Pixbuf.new_from_data,它看起来很有用:

fill = GdkPixbuf.Pixbuf.new_from_data(b'\xff\x00\xff', GdkPixbuf.Colorspace.RGB,
    False, 8, 1, 1, 3)

然而,这也不起作用。它不仅将像素设置为错误的颜色,还在set_icon()的多次调用中将其设置为不同的颜色; print(fill.get_pixels())给了我b'\x00\x00\x00' ...我用错了吗?我绑了各种不同的参数,但都给出了相同的结果......

我还发现了一个修改gdk_pixbuf_get_pixels()结果的C示例,因为这会返回指向图像数据的指针。但这不是你可以在Python(AFAIK)中做的事情。

我想要完成的一些背景:
我有一个小托盘应用程序来显示我的笔记本电脑的电池状态;它会填满电池图标,以指示电池剩余电量。低于一定百分比,颜色从绿色变为红色(这适用于上面的例子),但我希望在这方面有更多的灵活性;例如。允许其他人设置自己的绿色,或使用紫色,或其他任何东西。

1 个答案:

答案 0 :(得分:1)

事实证明这很简单,但阅读文档并不是很明显:

# red, green, blue, alpha
color = 0xeeff2dff

# Create blank 1x1 image
fill = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 1, 1)

# Fill entire image with color
fill.fill(color)

我原来的解决方案,留在这里用于存档目的;这是更复杂的&amp;不使用透明度,但它可能更适合更高级的操作

更糟糕的是,我最终使用GdkPixbuf.PixbufLoader.new_with_type,来自:

list(map(lambda x: x.get_name(), GdkPixbuf.Pixbuf.get_formats()))

我选择了最简单的图像格式,它似乎是&#34;便携式的任何地图格式&#34;或pnm

我用GIMP创建了一个简单的1x1图像,它给了我这些数据:

>>> open('test.pnm', 'rb').read()
b'P6\n# CREATOR: GIMP PNM Filter Version 1.1\n1 1\n255\n\xff\x00\xff'

最后3个字节(\xff\x00\xff)是我选择的颜色。

完整示例我最终使用:

color = b'\xee\xff\x2d'

px = GdkPixbuf.PixbufLoader.new_with_type('pnm')
px.write(b'P6\n\n1 1\n255\n' + color)
px.write(color)
px.close()
fill = px.get_pixbuf()

然后我可以使用fill与原始示例一样fill.copy_area()

这是一种解决方法,但可以接受......

PS。
从文档来看,GdkPixbuf.Pixbuf.new_from_data看起来是做这件事的最佳选择,但似乎已经破了......无论我做什么,我都无法工作......