import struct def image_dimensions(content: bytes) -> tuple[int, int] | None: """Largeur/hauteur RÉELLES (en pixels) d'une image, lues directement dans ses en-têtes — SANS dépendance externe (Pillow serait la solution habituelle, mais un simple parsing des formats courants suffit ici et évite d'ajouter une dépendance binaire lourde juste pour ça). Renvoie None si le format n'est pas reconnu (ex. SVG vectoriel sans taille fixe) — l'appelant retombe alors sur les valeurs par défaut du schéma (voir screens/scenes/add_scene_object.py).""" if content[:8] == b"\x89PNG\r\n\x1a\n": if len(content) >= 24: width, height = struct.unpack(">II", content[16:24]) return width, height return None if content[:6] in (b"GIF87a", b"GIF89a"): if len(content) >= 10: width, height = struct.unpack("= 26: width, height = struct.unpack(" tuple[int, int] | None: chunk = content[12:16] if chunk == b"VP8X" and len(content) >= 30: width = 1 + (content[24] | (content[25] << 8) | (content[26] << 16)) height = 1 + (content[27] | (content[28] << 8) | (content[29] << 16)) return width, height if chunk == b"VP8 " and len(content) >= 30: width, height = struct.unpack("= 25: b = content[21:25] bits = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24) width = (bits & 0x3FFF) + 1 height = ((bits >> 14) & 0x3FFF) + 1 return width, height return None def _jpeg_dimensions(content: bytes) -> tuple[int, int] | None: i = 2 n = len(content) while i + 9 < n: if content[i] != 0xFF: i += 1 continue marker = content[i + 1] if marker in (0xD8, 0x01) or 0xD0 <= marker <= 0xD7: i += 2 continue if marker == 0xD9: break seg_len = struct.unpack(">H", content[i + 2 : i + 4])[0] if 0xC0 <= marker <= 0xCF and marker not in (0xC4, 0xC8, 0xCC): height, width = struct.unpack(">HH", content[i + 5 : i + 9]) return width, height i += 2 + seg_len return None