-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Closed as not planned
Closed as not planned
Copy link
Description
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))Metadata
Metadata
Assignees
Labels
No labels