From 7fceb86a7b6a7f99db8fd74d75b84ee12fa16ae6 Mon Sep 17 00:00:00 2001 From: hyugogirubato <65763543+hyugogirubato@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:54:21 +0200 Subject: [PATCH] Native extraction of ICO --- cbz/utils.py | 60 +++++++++++----------------------------------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/cbz/utils.py b/cbz/utils.py index 8064afb..7d62a4e 100644 --- a/cbz/utils.py +++ b/cbz/utils.py @@ -1,56 +1,11 @@ -import struct from enum import Enum from io import BytesIO from PIL import Image +from PIL.IcoImagePlugin import IcoFile from path import Path -def extract_ico(path: Path) -> list[Image]: - """ - Extracts all the images from an ICO file. - - Args: - path (Path): Path to the ICO file. - - Returns: - list[Image]: List of PIL Image objects representing the icons in the ICO file. - """ - # https://stackoverflow.com/questions/74341558/how-do-i-read-a-different-size-of-an-icon-file - # https://en.wikipedia.org/wiki/ICO_(file_format) - icons = [] - - # Constants for ICO file structure - ICONDIRSIZE = 6 - ICONDIRENTRYSIZE = 16 - - # Read the entire ICO file content - d = path.read_bytes() - - # Extract ICONDIR header - hdrReserved, hdrImageType, hdrNumImages = struct.unpack(' any: """ Provides a default value based on the expected type of an attribute. @@ -139,7 +94,16 @@ def ico_to_png(path: Path) -> BytesIO: Returns: BytesIO: In-memory PNG file of the largest icon. """ - icons = extract_ico(path) + # Open the ICO file and read its content + image = Image.open(BytesIO(path.read_bytes())) + assert image.format == 'ICO', 'Unsupported image format' + + # Get the ICO file object and find the largest icon size + icon: IcoFile = image.ico + max_size = max(icon.sizes(), key=lambda x: x[0] + x[1]) + largest_image = icon.getimage(size=max_size) + + # Save the largest icon as PNG format to an in-memory BytesIO object content = BytesIO() - icons[-1].save(content, format='PNG') + largest_image.save(content, format='PNG') return content