Skip to content

Instantly share code, notes, and snippets.

@hitode909
Created October 15, 2026 08:36
Show Gist options
  • Select an option

  • Save hitode909/d0e39646099d82618efba24fd2786fd9 to your computer and use it in GitHub Desktop.

Select an option

Save hitode909/d0e39646099d82618efba24fd2786fd9 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""Create an intentionally non-Exif-compliant JPEG with recursively nested JPEG thumbnails.
Requires Pillow: python -m pip install Pillow
Example: python generate_matryoshka_exif.py input.jpg output.jpg --sizes 160 96 48
"""
import argparse
import io
import struct
from pathlib import Path
from PIL import Image
def thumbnail(source: Image.Image, size: int, quality: int) -> bytes:
image = source.copy().convert('RGB')
image.thumbnail((size, size), Image.Resampling.LANCZOS)
buf = io.BytesIO()
image.save(buf, format='JPEG', quality=quality, optimize=True)
return buf.getvalue()
def exif_app1(child: bytes) -> bytes:
# A minimal little-endian TIFF with an empty IFD0 and a 3-entry IFD1.
tiff = bytearray(b'II' + struct.pack('<HI', 42, 8))
tiff += struct.pack('<HI', 0, 14) # IFD0: 0 entries, IFD1 at 14
tiff += struct.pack('<H', 3) # IFD1: 3 entries
tiff += struct.pack('<HHI', 259, 3, 1) + struct.pack('<H', 6) + b'\0\0'
tiff += struct.pack('<HHII', 513, 4, 1, 56)
tiff += struct.pack('<HHII', 514, 4, 1, len(child))
tiff += struct.pack('<I', 0)
assert len(tiff) == 56
payload = b'Exif\0\0' + tiff + child
length = len(payload) + 2
if length > 65535:
raise ValueError(f'APP1 requires {length} bytes (maximum 65535). '
'Try smaller thumbnail sizes or lower quality.')
return b'\xff\xe1' + struct.pack('>H', length) + payload
def attach(jpeg: bytes, child: bytes) -> bytes:
if not jpeg.startswith(b'\xff\xd8'):
raise ValueError('Not a JPEG stream')
return jpeg[:2] + exif_app1(child) + jpeg[2:]
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('input', type=Path)
parser.add_argument('output', type=Path)
parser.add_argument('--sizes', nargs='+', type=int, default=[160, 96, 48],
help='thumbnail maximum dimensions outer to inner, default: 160 96 48')
parser.add_argument('--qualities', nargs='+', type=int, default=[60, 55, 45],
help='JPEG qualities outer to inner, default: 60 55 45')
args = parser.parse_args()
if not args.sizes or len(args.sizes) != len(args.qualities):
parser.error('--sizes and --qualities must have the same nonzero count')
if any(s <= 0 for s in args.sizes) or any(not 1 <= q <= 95 for q in args.qualities):
parser.error('sizes must be positive; qualities must be 1..95')
if args.input.resolve() == args.output.resolve():
parser.error('output must differ from input')
with Image.open(args.input) as image:
if image.format != 'JPEG':
parser.error('input must be JPEG')
source = image.copy()
layers = [thumbnail(source, sz, q) for sz, q in zip(args.sizes, args.qualities)]
nested = layers[-1]
for parent in reversed(layers[:-1]):
nested = attach(parent, nested)
outer = args.input.read_bytes()
result = attach(outer, nested)
args.output.write_bytes(result)
print(f'Created {args.output} ({len(result)} bytes; {len(layers)} nested thumbnails)')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment