I am trying to make a window manager in python 3 and I need to find out how to render 16x16 window icons.
I have used Pillow and Xlib to render a dummy image, and I was expecting that it would work, but nope! It didn't.
The test program is mostly just initializing the window and generating the image, the faulty part is (at least one problem, there probably are more): screen.default_visual. I can't find any documentation on ANY of this, any help would be appreciated.
from Xlib import display, X, Xutil
from PIL import Image, ImageDraw
import os
def renderPng(image_path, width, height, x=50, y=50):
img = Image.open(image_path)
if img.mode != 'RGB':
img = img.convert('RGB')
image_data = img.tobytes("raw", "RGB")
disp = display.Display()
screen = disp.screen()
root = screen.root
visual = screen.root_visual
depth = screen.root_depth
win = root.create_window(
x, y,
width, height,
1,
depth,
X.InputOutput,
visual,
background_pixel=screen.white_pixel,
event_mask=X.ExposureMask | X.KeyPressMask | X.StructureNotifyMask
)
win.set_wm_name("PNG image")
win.map()
gc = win.create_gc(
foreground=screen.black_pixel,
background=screen.white_pixel
)
ximage = X.Image(
data=image_data,
width=16,
height=16,
depth=depth,
bitmap_unit=8,
bitmap_pad=32,
byte_order=X.LSBFirst,
bitmap_bit_order=X.LSBFirst,
format=X.ZPixmap,
bytes_per_line=16 * 3
)
while True:
event = disp.next_event()
if event.type == X.Expose:
if event.count == 0:
win.put_image(gc, ximage, 0, 0, 0, 0, 16, 16)
disp.flush()
elif event.type == X.KeyPress:
break
elif event.type == X.ConfigureNotify:
pass
win.destroy()
disp.close()
if __name__ == '__main__':
dummy = "dummy.png"
if not os.path.exists(dummy):
img = Image.new('RGB', (16, 16), color = 'red')
d = ImageDraw.Draw(img)
d.text((1,1), "abc", fill=(255,255,255))
img.save(dummy)
renderPng(dummy, 200, 200, 100, 100)
And the code gives me this error:
Traceback (most recent call last):
File "/home/spincube/x/test.py", line 63, in <module>
renderPng(dummy, 200, 200, 100, 100)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/spincube/x/test.py", line 31, in renderPng
ximage = X.Image(
^^^^^^^
AttributeError: module 'Xlib.X' has no attribute 'Image'
UPDATE: I changed default_visual to root_visual.
I couldn't find default_visual but there is root_visual
I couldn't find X.Image but there is put_pil_image() which can put directly PIL.Image without converting to bytes and without X.Image
from Xlib import display, X #, Xutil
from PIL import Image, ImageDraw
import os
def render_png(image_path, width, height, x=50, y=50):
img = Image.open(image_path)
if img.mode != 'RGB':
img = img.convert('RGB')
#image_data = img.tobytes("raw", "RGB")
disp = display.Display()
screen = disp.screen()
root = screen.root
visual = screen.root_visual # no exists `default_visual`
depth = screen.root_depth
win = root.create_window(
x, y,
width, height,
1,
depth,
X.InputOutput,
visual,
background_pixel=screen.white_pixel,
event_mask=X.ExposureMask | X.KeyPressMask | X.StructureNotifyMask
)
win.set_wm_name("PNG image")
win.map()
gc = win.create_gc(
foreground=screen.black_pixel,
background=screen.white_pixel
)
while True:
event = disp.next_event()
if event.type == X.Expose:
if event.count == 0:
win.put_pil_image(gc, 0, 0, img)
disp.flush()
elif event.type == X.KeyPress:
break
elif event.type == X.ConfigureNotify:
pass
win.destroy()
disp.close()
if __name__ == '__main__':
dummy = "dummy.png"
if not os.path.exists(dummy):
img = Image.new('RGB', (16, 16), color = 'red')
d = ImageDraw.Draw(img)
d.text((1,1), "abc", fill=(255,255,255))
img.save(dummy)
render_png(dummy, 200, 200, 100, 100)

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With