Skip to content

Image.open is generating a warning with icon files that contain PNG images #9013

@phpjunkie420

Description

@phpjunkie420

I'm posting this 'cause of a warning I've gotten when opening icon files, and what I did to get around the warning.

  • OS: Windows 11 24H2 (OS Build 261000.4315) 10.0.26100 <- this was generated by python, and python could have miss reporting my actual version number 'cause of my heavily modified installation of windows.
  • Python: 3.12.9
  • Pillow: 11.1

An .ico file is a container designed to hold multiple images at different sizes and color depths (e.g., 16x16, 32x32, 256x256 pixels). This allows Windows to pick the best-looking image for a specific situation, like the taskbar, a desktop shortcut, or a detailed view in Explorer.

  • Historically, these embedded images were always simple bitmaps (DIBs).
  • Today, you can place a compressed PNG image inside that container instead. This is highly recommended because PNGs offer excellent compression and full alpha transparency, resulting in smaller files and better-looking icons. .ico

The StackOverflow.ico contains 256x256, 512x512, 768x768, and 1024x1024 PNG images, plus the typical bitmap images (16x16 20x20, 24x24, 32x32, etc.).

import io
import struct
import typing
import pathlib

from PIL import Image

# PIL\IcoImagePlugin.py:357: UserWarning: Image was not the expected size warnings.warn("Image was not the expected size")
icon_file = pathlib.Path(__file__).parent / 'StackOverflow.ico'
image = Image.open(str(icon_file)) 

# workaround
icon_data = icon_file.read_bytes()

count = struct.unpack("<H", icon_data[4:6])[0]
for i in range(count):
    entry_offset = 6 + (16 * i)
    if entry_offset + 16 > len(icon_data):
        continue

    length = struct.unpack("<I", icon_data[entry_offset + 8:entry_offset + 12])[0]
    offset = struct.unpack("<I", icon_data[entry_offset + 12:entry_offset + 16])[0]

    image: typing.Optional[Image.Image] = None
    with io.BytesIO() as byte_stream:
        image_content = icon_data[offset:offset + length]
        if image_content.startswith(b'\x89PNG\r\n\x1a\n'):
            byte_stream.write(image_content)
        else:
            byte_stream.write(b'\x00\x00\x01\x00')
            byte_stream.write(struct.pack("<H", 1))
            byte_stream.write(icon_data[entry_offset:entry_offset + 12])
            byte_stream.write(struct.pack("<I", 22))
            byte_stream.write(image_content)

        byte_stream.seek(0)
        image = Image.open(byte_stream)
        image.load()

    with image:
        output_path = icon_file.parent / 'out' / f'icon_{image.width}x{image.height}.png'
        output_path.parent.mkdir(parents = True, exist_ok = True)
        image.save(fp = str(output_path), format = 'png' )

    print(output_path.name)

Through trial and error, I was able to figure out that it was these bytes above the PNG images that is generating the warning . . .

byte_stream.write(b'\x00\x00\x01\x00')
byte_stream.write(struct.pack("<H", 1))
byte_stream.write(icon_data[entry_offset:entry_offset + 12])
byte_stream.write(struct.pack("<I", 22))

StackOverflow.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions