pythonglfw

Set window icon by glfw in python


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

Solution

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