2014-11-03 121 views
1

我使用Gtk.StatusIcon,並且想要更改某些像素的顏色;我有一段代碼,用一個我想要設置的顏色加載一個1x1像素的PNG文件,然後將它複製到圖標Pixbuf中。
儘管這樣做有效,但它有一個明顯的缺點,即必須爲每種顏色創建1x1像素,因此我無法使用任意顏色,只能使用爲圖像創建的預定義顏色。更改GdkPixbuf(GTK3)中像素的顏色

如何將像素設置爲任意RGBA顏色?

我現在使用的代碼(簡化用於演示目的):我試圖創建與GdkPixbuf.PixbufLoader一個新的pixbuf對象,但這似乎期待一個PNG圖像,而不是一個字節對象

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

,所以這是不是非常有幫助:

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,看上去promossing:

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' ...我使用這個錯誤嗎?我綁了各種不同的參數,但都給出了相同的結果...

我還發現一個C示例修改了gdk_pixbuf_get_pixels()的結果,因爲這返回了一個指向圖像數據的指針。但這不是Python中可以做的事(AFAIK)。

我想要實現的一點背景:
我有一個小托盤應用程序來顯示筆記本電腦的電池狀態;它會填充電池圖標以指示剩餘電池電量。低於一定比例的顏色會從綠色變爲紅色(這與上面的例子一致),但我想在這方面有更多的靈活性;例如。讓其他人可以設置自己的綠色陰影,或使用紫色或其他任何東西。

+1

這不是一個直接回答你的問題,但您可以使用[符號圖標](https://developer.gnome.org/gtk3/stable/GtkIconTheme.html#gtk-icon-info-load-symbolic)完成目標,而不是操作原始圖像數據。 – ptomato 2014-11-05 04:31:45

回答

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) 

我原來的解決方案,在這裏留下備案;這是比較複雜&不透明度的工作,但它可能是更適合於更高級的操作

更瞎我結束了使用GdkPixbuf.PixbufLoader.new_with_type,從後:

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

我選擇了最簡單的圖像格式,它似乎是「便攜式anymap格式」或pnm

我創建了一個簡單的1x1圖片與GIMP,這給了我這樣的數據:

>>> 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看起來像是做這件事的最佳選擇,但它似乎打破了......我無法工作,無論我做什麼...