问题
I'm using Gtk.StatusIcon
, and want to change the colour of some pixels; 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.
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.
How do I set a pixel to an arbitrary RGBA colour?
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:
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:
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()
; print(fill.get_pixels())
gives me b'\x00\x00\x00'
... Am I using this wrong? 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. But this is not something you can do in 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.
回答1:
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:
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
.
I created a simple 1x1 image with GIMP, which gave me this data:
>>> 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.
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()
It's a bit of a workaround, but acceptable...
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...
来源:https://stackoverflow.com/questions/26713547/change-the-colour-of-pixels-in-a-gdkpixbuf-gtk3