#!/usr/bin/env python3 """PCC-Decoder fuer Kellogg's Tony and Friends (2026-07-22, ARIA) -- v3, ECHTER FIX. Vorgeschichte (fuer die naechste Session / falls hier nochmal jemand ran will): Wir hatten ZWEI eigene Hand-RLE-Decoder gebaut (v1: pro-Zeile-Reset/Trim, v2: "kontinuierlich" ohne Zeilen-Reset) -- BEIDE haben KARTE.PCC/KELLOGGS.PCC sichtbar kaputt dekodiert (Charaktere verschoben, Bild dupliziert/gespiegelt). Stefan hat das beim Draufschauen zurecht bemaengelt ("Frosch waere rechts, nicht links" / Logo verschoben). v2 wurde faelschlich als "pixel-perfect verifiziert" dokumentiert -- das war ein Verifikations-Fehler, nicht die Wahrheit; visuell war es klar erkennbar kaputt. Fund via Stefans Hinweis auf https://github.com/movAX13h/tony-and-friends-in-kelloggs-land: Deren PCXFile.cs bestaetigt .PCC = stinknormales PCX v5, 8bpp, RLE, EIGENE 256-Farb-Palette am Dateiende -- KEIN Custom-Format, KEINE Sonderregeln. Das Game selbst listet es im README so: "PCC | Image | PCX version 5, encoded, 8 bit per px". ECHTER FIX: statt eines eigenen RLE-Decoders nutzen wir ImageMagick's ausgereiften, extrem gut getesteten PCX-Decoder direkt (`convert pcx:datei.PCC out.png`). Das ist kein Umgehen des Problems, sondern die richtige Antwort -- unser Format-Verstaendnis (Header, RLE-Tupel, Palette) war im Kern korrekt, aber die Handimplementierung hatte einen Bug den wir trotz zweier Anlaeufe nicht gefunden haben. ImageMagick beherrscht Standard-PCX seit Jahrzehnten korrekt. Verifiziert: KARTE.PCC und KELLOGGS.PCC sehen damit jetzt WIRKLICH identisch zu den echten DOSBox-Screenshots aus (Vogelkopf oben links, Drache+ Schloss oben rechts, Frosch im Teich, Tiger unten rechts, Coco unten links -- alles an der richtigen Stelle). Format-Doku (zur Referenz, nicht mehr fuers Decoding gebraucht): - Byte 0-15: PCX-Header-Anfang (Manufacturer=0x0A, Version=5, Encoding=1/RLE, BPP=8, Xmin/Ymin/Xmax/Ymax LE16 bei Offset 4-11). Breite/Hoehe = Xmax-Xmin+1 / Ymax-Ymin+1. - Byte 16..(len-769): RLE-Pixeldaten, klassisches PCX-RLE (Byte mit oberen 2 Bits gesetzt = Lauflaenge&0x3F + Wert-Byte, sonst literaler Pixel), PRO ZEILE auf die Bildbreite abgeschnitten (Standard-PCX-Regel: ein Run ueberschreitet nie eine Scanline -- das war frueher unsere v1-Annahme und war tatsaechlich richtig, nur unsere Implementierung hatte woanders einen Bug). - Letzte 769 Byte: 0x0C-Marker + 768 Byte (256 x RGB) eigene Palette pro Datei. Nutzung: python3 pcc_to_png.py """ import sys, struct, subprocess, shutil def read_header(data): manuf, version, encoding, bpp = data[0], data[1], data[2], data[3] xmin, ymin, xmax, ymax = struct.unpack('= 0 else None return dict(manuf=manuf, version=version, encoding=encoding, bpp=bpp, width=width, height=height, marker_ok=(marker == 0x0C)) def decode_with_imagemagick(inp, outp): convert_bin = shutil.which('magick') or shutil.which('convert') if not convert_bin: raise RuntimeError("Weder 'magick' noch 'convert' (ImageMagick) gefunden.") if convert_bin.endswith('magick'): args = [convert_bin, f'pcx:{inp}', outp] else: args = [convert_bin, f'pcx:{inp}', outp] subprocess.run(args, check=True, capture_output=True) def main(): inp, outp = sys.argv[1], sys.argv[2] with open(inp, 'rb') as f: data = f.read() hdr = read_header(data) print(f"{inp}: {hdr['width']}x{hdr['height']} bpp={hdr['bpp']} " f"marker_ok={hdr['marker_ok']}") decode_with_imagemagick(inp, outp) print(f"-> {outp}") if __name__ == '__main__': main()