I am using pyGLFW to create a window and I want to set an icon for the window. I tried to search on the glfw website but it does not support Python.
I am encountering an error when passing the image as a parameter. Please show me how to use glfw.set_window_icon()
correctly.
My current code:
def set_icon(self, icon: str):
img = cv2.imread(icon, cv2.IMREAD_UNCHANGED)
if img is None:
return False
h, w = img.shape[:2]
if img.shape[2] == 3:
alpha = numpy.ones((h, w, 1), dtype = numpy.uint8) * 255
img = numpy.concatenate((img, alpha), axis = 2)
img = img.astype(numpy.uint8)
img_data = img.flatten()
glfw_img = (w, h, img_data)
glfw.set_window_icon(self.window, 1, [glfw_img]) # self.window = glfw.create_window(...)
All libraries I'm using:
Error Message:
File "c:\...\lib\graphic\window.py", line 303, in set_icon
glfw.set_window_icon(self.window, 1, [glfw_img])
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Legion\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\glfw\__init__.py", line 2733, in set_window_icon
_images[i].wrap(image)
~~~~~~~~~~~~~~~^^^^^^^
File "C:\Users\Legion\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\glfw\__init__.py", line 275, in wrap
self.pixels_array[i][j][k] = pixels[i][j][k]
~~~~~~~~~^^^
TypeError: 'int' object is not subscriptable
An error with pixels[i][j][k]
may suggest that it needs original array 3D instead of .flatten()
.
The error shows which line of code makes problem so you can check source code /glfw/__init__.py.
else:
self.width, self.height, pixels = image
array_type = ctypes.c_ubyte * 4 * self.width * self.height
self.pixels_array = array_type()
for i in range(self.height):
for j in range(self.width):
for k in range(4):
self.pixels_array[i][j][k] = pixels[i][j][k]
And this also suggests that it needs image as 3D array, not flatten.
It also suggests that it has to be image with transparency RGBA because last loop uses range(4)
.
BTW:
Code before else also suggests that you can use image loaded with PIL (instead of OpenCV) and it will convert it to RGBA.
if hasattr(image, 'size') and hasattr(image, 'convert'):
# Treat image as PIL/pillow Image object
self.width, self.height = image.size
array_type = ctypes.c_ubyte * 4 * (self.width * self.height)
self.pixels_array = array_type()
pixels = image.convert('RGBA').getdata()
for i, pixel in enumerate(pixels):
self.pixels_array[i] = pixel
To check my guesses I made full working code.
I removed .flatten()
.
I had to convert from BGR to RGB because OpenCV keeps image as BGR.
I also made code which use PIL instead of OpenCV and it is simpler.
from PIL import Image
img = Image.open(icon)
glfw_img = img # <--- without w, h and without ()
glfw.set_window_icon(window, 1, [glfw_img])
I took example code from official repo: https://github.com/FlorianRhiem/pyGLFW
And here is full working code:
import cv2
import numpy
import glfw
# image generated with ImageMagick:
# convert -size 32x32 -define png:color-type=2 canvas:white empty.png
# or with Python and PIL
# python3 -c 'from PIL import Image;Image.new("RGB", (32,32), color="white").save("empty.png")'
icon = 'empty.png'
def add_icon_pillow(window):
from PIL import Image
img = Image.open(icon)
glfw_img = img # <--- without w, h and without ()
glfw.set_window_icon(window, 1, [glfw_img])
def add_icon_cv2(window):
img = cv2.imread(icon, cv2.IMREAD_UNCHANGED)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # <--- convert from BGR to RGB
if img is None:
return False
h, w = img.shape[:2]
if img.shape[2] == 3:
alpha = numpy.ones((h, w, 1), dtype = numpy.uint8) * 255
img = numpy.concatenate((img, alpha), axis = 2)
img = img.astype(numpy.uint8)
#img = img.flatten() # <--- remove flatten()
glfw_img = (w, h, img)
glfw.set_window_icon(window, 1, [glfw_img])
def main():
# Example code from official repo: https://github.com/FlorianRhiem/pyGLFW
# Initialize the library
if not glfw.init():
return
# Create a windowed mode window and its OpenGL context
window = glfw.create_window(640, 480, "Hello World", None, None)
if not window:
glfw.terminate()
return
add_icon_cv2(window)
#add_icon_pillow(window)
# Make the window's context current
glfw.make_context_current(window)
# Loop until the user closes the window
while not glfw.window_should_close(window):
# Render here, e.g. using pyOpenGL
# Swap front and back buffers
glfw.swap_buffers(window)
# Poll for and process events
glfw.poll_events()
glfw.terminate()
if __name__ == "__main__":
main()