#!/usr/bin/env python3 import io import struct import sys import zlib from os.path import basename from PIL import Image def png2toif(input_data): def process_rgb(w, h, pix): data = bytes() for j in range(h): for i in range(w): r, g, b = pix[i, j] c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3) data += struct.pack(">H", c) return data def process_grayscale(w, h, pix): data = bytes() for j in range(h): for i in range(w // 2): l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j] c = (l1 & 0xF0) | (l2 >> 4) data += struct.pack(">B", c) return data im = Image.open(io.BytesIO(input_data)) w, h = im.size if im.mode not in ["RGB", "L"]: raise ValueError("Unknown mode:", im.mode) if im.mode == "L": if w % 2 > 0: raise ValueError("PNG file must have width divisible by 2") pix = im.load() if im.mode == "RGB": pixeldata = process_rgb(w, h, pix) else: pixeldata = process_grayscale(w, h, pix) z = zlib.compressobj(level=9, wbits=10) zdata = z.compress(pixeldata) + z.flush() zdata = zdata[2:-4] # strip header and checksum data = b"" if im.mode == "RGB": data += b"TOIf" else: data += b"TOIg" data += struct.pack("> 8, h & 0xFF, h >> 8) ) l = len(zdata) f.write(" // compressed data length (32-bit)\n") f.write( " 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n" % (l & 0xFF, (l >> 8) & 0xFF, (l >> 16) & 0xFF, l >> 24) ) f.write(" // compressed data\n") f.write(" ") for b in zdata: f.write(" 0x%02x," % b) f.write("\n};\n") """ def toif2png(data): def process_rgb(w, h, data): pix = bytearray(w * h * 3) for i in range(w * h): c = (data[i * 2] << 8) + data[i * 2 + 1] pix[i * 3 + 0] = (c & 0xF800) >> 8 pix[i * 3 + 1] = (c & 0x07C0) >> 3 pix[i * 3 + 2] = (c & 0x001F) << 3 return bytes(pix) def process_grayscale(w, h, data): pix = bytearray(w * h) for i in range(w * h // 2): pix[i * 2 + 0] = data[i] & 0xF0 pix[i * 2 + 1] = (data[i] & 0x0F) << 4 return bytes(pix) if data[:4] != b"TOIf" and data[:4] != b"TOIg": raise ValueError("Unknown TOIF header") format = data[:4].decode().lower() w, h = struct.unpack("