69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Packt ein Bild als Argonaut-.cor (Gegenstück zu cor2png.py).
|
|
|
|
Das Bild wird auf 640x480 RGB gebracht und mit dem LZ-Schema des Spiels
|
|
komprimiert:
|
|
n < 0x80 -> n Bytes Rohdaten folgen (n = 1..127)
|
|
1LLL oooo oooooooo -> kopiere L+3 Bytes (3..10) ab o Bytes (1..4095) zurück
|
|
Aufruf: png2cor.py eingabe.png ausgabe.cor (benötigt Pillow)
|
|
"""
|
|
import struct
|
|
import sys
|
|
|
|
MAGIC = bytes.fromhex('1798af89fe42d112')
|
|
MAXOFF, MINLEN, MAXLEN = 0x0FFF, 3, 10
|
|
|
|
|
|
def pack(raw):
|
|
out = bytearray()
|
|
lit = bytearray()
|
|
last = {} # 3-Byte-Präfix -> Liste letzter Positionen
|
|
|
|
def flush():
|
|
for k in range(0, len(lit), 127):
|
|
part = lit[k:k + 127]
|
|
out.append(len(part))
|
|
out.extend(part)
|
|
lit.clear()
|
|
|
|
i, n = 0, len(raw)
|
|
while i < n:
|
|
best_len, best_off = 0, 0
|
|
if i + MINLEN <= n:
|
|
key = raw[i:i + 3]
|
|
for p in reversed(last.get(key, ())):
|
|
off = i - p
|
|
if off > MAXOFF:
|
|
break
|
|
ln = 3
|
|
while ln < MAXLEN and i + ln < n and raw[p + ln] == raw[i + ln]:
|
|
ln += 1
|
|
if ln > best_len:
|
|
best_len, best_off = ln, off
|
|
if ln == MAXLEN:
|
|
break
|
|
step = best_len if best_len >= MINLEN else 1
|
|
for j in range(i, min(i + step, n - 2)):
|
|
lst = last.setdefault(raw[j:j + 3], [])
|
|
lst.append(j)
|
|
if len(lst) > 16:
|
|
del lst[0]
|
|
if best_len >= MINLEN:
|
|
flush()
|
|
out.append(0x80 | ((best_len - 3) << 4) | (best_off >> 8))
|
|
out.append(best_off & 0xFF)
|
|
i += best_len
|
|
else:
|
|
lit.append(raw[i])
|
|
i += 1
|
|
flush()
|
|
return MAGIC + struct.pack('<III', 1, len(raw), len(out)) + bytes(out)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
from PIL import Image
|
|
img = Image.open(sys.argv[1]).convert('RGB').resize((640, 480), Image.LANCZOS)
|
|
data = pack(img.tobytes())
|
|
open(sys.argv[2], 'wb').write(data)
|
|
print(f'{sys.argv[2]}: {len(data)} Bytes')
|