pythonimageicopython-imageio

How to resize images with imageio to get proper ICO files?


I want to save ICO files from images. imageio is working perfectly, but for horizontal images, it gave me an error.

This is my code:

import imageio
image = imageio.imread('image.png')
imageio.imwrite("image.ico", image)

Solution

  • I assume, you have problems opening the resulting ICO files, because the software you use simply expects square images of certain size(s) when opening ICO files!? Unfortunately, it seems that imageio.imwrite saves ICO files with only setting the larger dimension to default 16, 24, ... pixels, when feeding a non-square image. Suppose, we have such an image:

    Input

    And, we have some test code like this:

    import imageio
    
    # Read image
    img_io = imageio.imread('image.png')
    
    # Write ICO image
    imageio.imwrite('image.ico', img_io)
    

    The resulting image.ico has six images with dimensions 16 x 13, 24 x 19, and so on.

    If you want to resolve that, you should properly resize your image beforehand to get a square image. Actually, resizing images can be quite difficult when using imageio. Please, see this recent Q&A for some details. If you simply want to have a square image without keeping the aspect ratio, you might want to use skimage.transform.resize:

    import imageio
    from skimage.transform import resize
    
    # Read image
    img_io = imageio.imread('image.png')
    
    # Resize image
    img_io = resize(img_io, (200, 200))
    
    # Write ICO image
    imageio.imwrite('image.ico', img_io)
    

    Now, the resulting image.ico has six images with dimensions 16 x 16, 24 x 24, and so on.

    If you want to keep the aspect ratio of your image, you'd need to add proper borders to your image. There's this helpful Q&A on that issue. You could also add fancy, transparent borders solely using NumPy:

    import imageio
    import numpy as np
    
    # Read image
    img_io = imageio.imread('image.png')
    
    # Add transparent borders to image
    h, w = img_io.shape[:2]
    img = np.zeros((w, w, 4), np.uint8)
    img[30:h+30, :, :3] = img_io
    img[30:h+30, :, 3] = 255
    
    # Write ICO image
    imageio.imwrite('image.ico', img)
    

    Now, the resulting image.ico even has seven images with dimensions 16 x 16, ..., 256 x 256, since the modified image is large enough.

    ----------------------------------------
    System information
    ----------------------------------------
    Platform:      Windows-10-10.0.16299-SP0
    Python:        3.8.5
    imageio:       2.9.0
    NumPy:         1.19.5
    scikit-image:  0.18.1
    ----------------------------------------