#!/usr/bin/env python

"""
Convert Kobo RGB 565 (stdin) to PNG (stdout).

Assumes an 800x600 pixel input (compatible with 2013-era Kobo devices)
Note: image top-left is screen top-right.
"""

# The raw format stores the pixels sequentially in top-left
# reading order; each pixel is a 16-bit word packed into bytes
# little-endian; the word stores (from high to low) 5 bits of
# Red, 6 bits of Green, 5 bits of Blue:
#  15   11 10      5 4     0
# +-------+---------+-------+
# |  Red  |  Green  |  Blue |
# +-------+---------+-------+
#  15         8 7          0
#  \          / \          /
#    byte N+1      byte N

import struct

import png

class Kobo565:

    @staticmethod
    def make_array(fil):
        """Convert RAW file *fil* to a 2D array."""
        w = 800
        h = 600
        for i in range(h):
          row = []
          s = fil.read(w*2)
          pixels = struct.unpack('<800H', s)
          for p in pixels:
            r = p >> 11
            g = (p >> 5) & 0x3f
            b = p & 0x1f
            r = (r * 255) / 31.0
            g = (g * 255) / 63.0
            b = (b * 255) / 31.0
            row.extend([int(round(x)) for x in [r, g, b]])
          yield row


def main():
    import sys
    outname = None
    arg = sys.argv[1:]
    while arg:
        if arg[0] == '-o':
            outname = arg[1]
            arg = arg[2:]
        elif arg[0] == '--':
            arg = arg[1:]
            break
        elif arg[0].startswith('-'):
            raise Exception("Unknown option %r" % arg[0])
        else:
            break

    array = Kobo565.make_array(sys.stdin)
    image = png.from_array(array, 'RGB', info=dict(height=600))

    if outname is None:
        image.save(sys.stdout)
    else:
        image.save(outname)

if __name__ == '__main__':
    main()
