All formats

Pillow

LanguagePython 3
LicenseMIT-CMU (permissive)
Repositorygithub.com/python-pillow/Pillow
DocumentationICO in the Pillow image file formats docs
Depends onnothing to install separately (wheels include the native code)
Read / writeICO yes / yes (PNG or BMP entries); CUR read only

Pillow opens ICO files like any other image. Image.open loads the largest entry by default; im.info["sizes"] lists every size in the file and setting im.size before loading picks one. When saving as ICO, Pillow scales the image to each size you ask for and stores the entries as PNG (or BMP with bitmap_format="bmp").

CUR files open read-only (the largest cursor; animated .ani cursors aren’t supported). Pillow doesn’t return the cursor hotspot.

Installation#

Shell
pip install pillow

Basic usage: convert ICO to PNG#

Python
from PIL import Image

with Image.open("app.ico") as im:
    print(im.size, im.mode)         # largest entry, e.g. (256, 256) RGBA
    print(sorted(im.info["sizes"]))  # every size in the file
    im.save("app.png")

How to open a specific icon size#

Python
from PIL import Image

with Image.open("app.ico") as im:
    if (32, 32) in im.info["sizes"]:
        im.size = (32, 32)   # must be set before the image is loaded
    im.load()
    im.save("app-32.png")

im.ico.getimage((16, 16)) returns a new image for one size, and im.ico.frame(i) returns entry i (Pillow sorts entries from largest to smallest).

How to create a multi-size favicon.ico#

Save one large square image with the sizes you want. Pillow resizes it for each entry and skips sizes larger than the source:

Python
from PIL import Image

with Image.open("logo.png") as logo:
    logo = logo.convert("RGBA")
    logo.save("favicon.ico", sizes=[(16, 16), (32, 32), (48, 48)])
    logo.save("app.ico", sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (256, 256)])

Without sizes, Pillow writes 16, 24, 32, 48, 64, 128 and 256 (up to the source size).

How to use hand-drawn small sizes#

append_images replaces the scaled-down versions with your own images of the same size:

Python
from PIL import Image

big = Image.open("icon256.png")
small = [Image.open(f) for f in ("icon16.png", "icon32.png", "icon48.png")]
big.save("app.ico", sizes=[(16, 16), (32, 32), (48, 48), (256, 256)], append_images=small)

How to write BMP entries instead of PNG#

PNG entries are smaller but need Windows Vista or later. For the widest compatibility:

Python
logo.save("app.ico", sizes=[(16, 16), (32, 32), (48, 48)], bitmap_format="bmp")

Tips#