简体   繁体   English

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

[英]Change the colour of pixels in a GdkPixbuf (GTK3)

I'm using Gtk.StatusIcon , and want to change the colour of some pixels; 我正在使用Gtk.StatusIcon ,并且想要更改某些像素的颜色; I have a working piece of code, this loads a 1x1 pixel PNG file with the colour I want to set, and then copies that to thhe icon Pixbuf. 我有一段工作代码,它将以我要设置的颜色加载一个1x1像素的PNG文件,然后将其复制到图标Pixbuf。
While this works, it has the obvious drawback of having to create a 1x1 pixel for every colour, so I can't use an arbitrary colour, only the predefined colours I created images for. 虽然这样做有效,但它的明显缺点是必须为每种颜色创建一个1x1像素,因此我不能使用任意颜色,只能使用我为其创建图像的预定义颜色。

How do I set a pixel to an arbitrary RGBA colour? 如何将像素设置为任意RGBA颜色?

The code I'm using now (simplified for demonstration purposes): 我现在使用的代码(出于演示目的而简化):

#!/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()

I tried creating a new Pixbuf object with GdkPixbuf.PixbufLoader , but this seems to expect a PNG image, not a bytes object, so this isn't very helpful: 我尝试使用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)

My next try was to use GdkPixbuf.Pixbuf.new_from_data , which looked promossing: 我的下一个尝试是使用GdkPixbuf.Pixbuf.new_from_data ,它看起来很吸引人:

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

However, this doesn't work either. 但是,这也不起作用。 It not only sets the pixels to the wrong colour, it also sets it to different colours on multiple invocations of set_icon() ; 它不仅将像素设置为错误的颜色,还将在多次调用set_icon()将其设置为不同的颜色; print(fill.get_pixels()) gives me b'\\x00\\x00\\x00' ... Am I using this wrong? print(fill.get_pixels())给我b'\\x00\\x00\\x00' ...我使用的是这个错误吗? I tied various different parameters, but all give the same result... 我绑定了各种不同的参数,但是所有参数都给出相同的结果...

I also found a C example which modified the result of gdk_pixbuf_get_pixels() , since this returns a pointer to the image data. 我还发现了一个C示例,该示例修改了gdk_pixbuf_get_pixels()的结果,因为这返回了指向图像数据的指针。 But this is not something you can do in Python (AFAIK). 但这不是您可以在Python(AFAIK)中执行的操作。

A little background of what I'm trying to accomplish: 我要完成的工作的一些背景知识:
I have a little tray application to show my laptop's battery status; 我有一个小托盘应用程序可以显示笔记本电脑的电池状态; it fills up the battery icon to give an indication of how much battery power is left. 它会填满电池图标,以指示剩余的电池电量。 Below a certain percentage the colour changes from green to red (this works with the above example), but I would like to have more flexibility in this; 低于一定百分比时,颜色从绿色变为红色(这适用于以上示例),但是我想在此方面具有更大的灵活性。 eg. 例如。 allowing other people to set their own shade of green, or use purple, or whatever. 允许其他人设置自己的绿色阴影,使用紫色或其他颜色。

It turned out to be fairly simple, but not at all obvious from reading the docs: 事实证明这相当简单,但通过阅读文档一点都不明显:

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

My original solution, left here for archival purposes; 我最初的解决方案,出于存档目的留在这里; this is more complicated & doesn't work with transparency, but it might be better suited for more advanced operations 这比较复杂并且不能透明化,但是可能更适合于更高级的操作

After more mucking about I ended up using GdkPixbuf.PixbufLoader.new_with_type , from: 经过更多的讨论之后,我最终使用了GdkPixbuf.PixbufLoader.new_with_type ,来自:

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

I choose the simplest image format, which appears to be the "portable anymap format" or pnm . 我选择了最简单的图像格式,这似乎是“便携式anymap格式”或pnm

I created a simple 1x1 image with GIMP, which gave me this data: 我使用GIMP创建了一个简单的1x1图像,它为我提供了以下数据:

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

The last 3 bytes ( \\xff\\x00\\xff ) is the colour I choose. 最后3个字节( \\xff\\x00\\xff )是我选择的颜色。

Full example I ended up using: 我最终使用的完整示例是:

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

I can then use fill as in the original example with fill.copy_area() 然后,可以使用fill.copy_area()像原始示例中那样使用fill

It's a bit of a workaround, but acceptable... 这是一种解决方法,但是可以接受...

PS. PS。
From the documentation, GdkPixbuf.Pixbuf.new_from_data looks like the best option to do this, but it seems broken... I can't it to work no matter what I do... 从文档中可以GdkPixbuf.Pixbuf.new_from_dataGdkPixbuf.Pixbuf.new_from_data似乎是执行此操作的最佳选择,但它似乎坏了...无论如何我都无法正常工作...

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

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