# requires PySerial and PIL! # http://pyserial.sourceforge.net/ # http://www.pythonware.com/products/pil/ import sys import time import serial import PIL.Image threshold = 128*[0] + 128*[0xFF] def main(): ser = serial.Serial('/dev/tty.usbserial-A1001MPC', 9600) grays = range(0, 256, 4) + range(255, -1, -4) try: for i in xrange(0x7FFFFFFF): gray = grays[i % len(grays)] ser.write('o') ser.write(image2frame(PIL.Image.new('L', (6, 6), gray))) time.sleep(0.02) except KeyboardInterrupt: print '' ser.close() return 0 def dither(original): """ Return a monohrome, Atkinson-dithered version of an image. """ dithered = original.copy() for y in range(dithered.size[1]): for x in range(dithered.size[0]): old = dithered.getpixel((x, y)) new = threshold[old] err = (old - new) >> 3 # divide by 8 dithered.putpixel((x, y), new) for nxy in [(x+1, y), (x+2, y), (x-1, y+1), (x, y+1), (x+1, y+1), (x, y+2)]: try: dithered.putpixel(nxy, dithered.getpixel(nxy) + err) except IndexError: pass return dithered def image2frame(image): """ Convert an image to a 1-bit representation, using no more than the top-left 8x8 pixels. """ image = dither(image) bytes = [] for row in range(min(8, image.size[1])): bytes.append(0x00) for col in range(min(8, image.size[0])): # use bitwise-or to assign each pixel on this row from left to right. # trust that getpixel() will return either 0x00 or 0xFF, thanks to dither(). bytes[-1] |= (image.getpixel((col, row)) & (1 << (7 - col))) return ''.join(map(chr, bytes)) if __name__ == '__main__': sys.exit(main())