#!/usr/bin/env python3
"""
Decode the PREV (preview thumbnail) section from a pm4n file and save as PNG.
Run: python3 decode_prev.py <file.pm4n>
"""
import struct, sys
from pathlib import Path

path = sys.argv[1]
data = open(path, 'rb').read()

prev_off = data.find(b'PREV')
print(f"PREV at 0x{prev_off:06X}")

# PREV section layout (from ANYCUBIC format docs and common reverse-engineering):
# +0x00  "PREV"
# +0x04  u32  section_length
# +0x08  u32  image_width
# +0x0C  u32  image_height
# +0x10  u32  image_data_length
# +0x14  image data (RGB565 or RLE)

for hdr_size in [0x14, 0x18, 0x10, 0x0C]:
    w = struct.unpack_from('<I', data, prev_off + 0x08)[0]
    h = struct.unpack_from('<I', data, prev_off + 0x0C)[0]
    dlen = struct.unpack_from('<I', data, prev_off + 0x10)[0]
    print(f"  PREV+0x08: w={w}, h={h}, dlen={dlen}")
    if 100 < w < 2000 and 100 < h < 2000:
        print(f"  -> plausible dimensions {w}x{h}, data at +0x14, {dlen} bytes")
        break

# Show first 64 bytes of PREV section
print(f"\nPREV raw (first 64 bytes):")
chunk = data[prev_off:prev_off+64]
for i in range(0, 64, 16):
    row = chunk[i:i+16]
    hex_p = ' '.join(f'{b:02X}' for b in row)
    u_vals = [struct.unpack_from('<I', row, j)[0] for j in range(0, min(16,len(row))-3, 4)]
    print(f"  +0x{i:02X}  {hex_p:<48}  {u_vals}")

# Try to decode as RGB565 (common for ANYCUBIC previews)
# Each pixel = 2 bytes, little-endian RGB565
# R = bits[15:11], G = bits[10:5], B = bits[4:0]
img_data_off = prev_off + 0x14
img_data_len = struct.unpack_from('<I', data, prev_off + 0x10)[0]
w = struct.unpack_from('<I', data, prev_off + 0x08)[0]
h = struct.unpack_from('<I', data, prev_off + 0x0C)[0]

print(f"\nAttempting RGB565 decode: {w}x{h}, {img_data_len} bytes at 0x{img_data_off:06X}")
if 0 < w < 2000 and 0 < h < 2000 and img_data_len == w * h * 2:
    print(f"  Size matches RGB565 ({w}*{h}*2={w*h*2}) ✓")
    try:
        from PIL import Image
        pixels = []
        raw = data[img_data_off:img_data_off + img_data_len]
        for i in range(0, len(raw)-1, 2):
            px = raw[i] | (raw[i+1] << 8)
            r = ((px >> 11) & 0x1F) << 3
            g = ((px >> 5) & 0x3F) << 2
            b = (px & 0x1F) << 3
            pixels.append((r, g, b))
        img = Image.new('RGB', (w, h))
        img.putdata(pixels)
        out = Path(path).with_suffix('.prev_thumb.png')
        img.save(out)
        print(f"  Saved thumbnail to {out}")
    except Exception as e:
        print(f"  Error: {e}")
else:
    print(f"  Size mismatch or bad dims, skipping decode")
    print(f"  Expected {w*h*2} bytes for RGB565, got {img_data_len}")
