#!/usr/bin/env python3 from PIL import Image import sys import struct import zlib if len(sys.argv) < 2: print('Usage png2toi image.png [mode]') sys.exit(1) ifn = sys.argv[1] gray = False if len(sys.argv) >= 3 and sys.argv[2] == 'g': gray = True if not ifn.endswith('.png'): print('Must provide PNG file') sys.exit(2) im = Image.open(ifn) w, h = im.size print('Opened %s ... %d x %d @ %s' % (ifn, w, h, im.mode)) if not gray: if not im.mode == 'RGB': print('PNG file must use RGB mode') sys.exit(3) else: if not im.mode == 'L': print('PNG file must use grayscale mode') sys.exit(3) if w % 2 > 0: print('PNG file must have width divisible by 2') sys.exit(4) pix = im.load() ofn = '%s.toi' % ifn[:-4] with open(ofn, 'wb') as f: if not gray: f.write(bytes('TOIa', 'ascii')) else: f.write(bytes('TOIg', 'ascii')) f.write(struct.pack('>HH', w, h)) data = bytes() if not gray: 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) else: 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) z = zlib.compressobj(level=9, wbits=10) zdata = z.compress(data) + z.flush() zdata = zdata[2:-4] # strip header and checksum f.write(zdata) print('Written %s ... %d bytes' % (ofn, 4 + 4 + len(zdata)))