Loading files
988743a91This file is pinned to the selected release. Download the original to open it in your design tool.
#!/usr/bin/env python3
"""Print pixel dimensions of image files (WebP, PNG, JPEG).
Reads image headers directly — no external dependencies required.
Usage:
python cmd/export/image_dimensions.py path/to/images/
python cmd/export/image_dimensions.py path/to/single-image.webp
"""
import struct
import sys
from pathlib import Path
def webp_dimensions(path: Path) -> tuple[int, int] | None:
"""Read width and height from a WebP file header.
Args:
path: Path to a WebP image file.
Returns:
Tuple of (width, height) or None if unreadable.
"""
with path.open("rb") as f:
header = f.read(30)
if len(header) < 30 or header[:4] != b"RIFF" or header[8:12] != b"WEBP":
return None
chunk = header[12:16]
if chunk == b"VP8 ":
w = (header[26] | (header[27] << 8)) & 0x3FFF
h = (header[28] | (header[29] << 8)) & 0x3FFF
return w, h
if chunk == b"VP8L":
bits = int.from_bytes(header[21:25], "little")
return (bits & 0x3FFF) + 1, ((bits >> 14) & 0x3FFF) + 1
if chunk == b"VP8X":
w = int.from_bytes(header[24:27], "little") + 1
h = int.from_bytes(header[27:30], "little") + 1
return w, h
return None
def png_dimensions(path: Path) -> tuple[int, int] | None:
"""Read width and height from a PNG file header.
Args:
path: Path to a PNG image file.
Returns:
Tuple of (width, height) or None if unreadable.
"""
with path.open("rb") as f:
header = f.read(24)
if len(header) < 24 or header[:8] != b"\x89PNG\r\n\x1a\n":
return None
w, h = struct.unpack(">II", header[16:24])
return w, h
def jpeg_dimensions(path: Path) -> tuple[int, int] | None:
"""Read width and height from a JPEG file header.
Args:
path: Path to a JPEG image file.
Returns:
Tuple of (width, height) or None if unreadable.
"""
with path.open("rb") as f:
if f.read(2) != b"\xff\xd8":
return None
while True:
marker = f.read(2)
if len(marker) < 2:
return None
if marker[0] != 0xFF:
return None
if marker[1] in (0xC0, 0xC1, 0xC2):
f.read(3) # length + precision
h, w = struct.unpack(">HH", f.read(4))
return w, h
length = struct.unpack(">H", f.read(2))[0]
f.read(length - 2)
return None
READERS = {
".webp": webp_dimensions,
".png": png_dimensions,
".jpg": jpeg_dimensions,
".jpeg": jpeg_dimensions,
}
def get_dimensions(path: Path) -> tuple[int, int] | None:
"""Get pixel dimensions for a supported image file.
Args:
path: Path to an image file (.webp, .png, .jpg, .jpeg).
Returns:
Tuple of (width, height) or None if format unsupported/unreadable.
"""
reader = READERS.get(path.suffix.lower())
return reader(path) if reader else None
def main():
"""Print dimensions for supported image files passed on the command line.
Raises:
SystemExit: If no input paths are provided.
"""
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <path> [path ...]", file=sys.stderr)
sys.exit(1)
for arg in sys.argv[1:]:
target = Path(arg)
if not target.exists():
print(f"{arg}: <not found>", file=sys.stderr)
continue
try:
files = sorted(target.iterdir()) if target.is_dir() else [target]
except OSError as exc:
print(f"{arg}: {exc}", file=sys.stderr)
continue
for f in files:
if f.suffix.lower() in READERS:
try:
dims = get_dimensions(f)
except OSError:
dims = None
if dims:
print(f"{f.name}: {dims[0]}x{dims[1]}")
else:
print(f"{f.name}: <unreadable>", file=sys.stderr)
if __name__ == "__main__":
main()