#!/usr/bin/env python

import Image, struct

def makegifbw(data, fp, transparent=False):
  (w, h) = (len(data[0]), len(data))
  def pix1(color):
    if color:
      return chr(1)
    else:
      return chr(0)
  rawdata = "".join([ "".join([ pix1(c) for c in line ]) for line in data ])
  im = Image.fromstring("L", (w,h), rawdata, "raw", "L")
  # header
  if transparent:
    fp.write('GIF89a')                    # magic GIF89
  else:
    fp.write('GIF87a')                    # magic GIF87
  fp.write(struct.pack('<HH', w, h))    # size
  fp.write('\x80')                      # flags (GLOBALCOLOR, 2^(0+1) COLORS)
  fp.write('\x00')                      # bgcolor index
  fp.write('\x00')                      # no aspect ratio
  # palettte
  fp.write('\xff\xff\xff')              # white
  fp.write('\x00\x00\x00')              # black
  if transparent:
    # graphic control extension block
    fp.write('\x21')                      # separator
    fp.write('\xf9')                      # magic
    fp.write('\x04')                      # size (fixed)
    fp.write('\x01')                      # flags (TRANSPARENT)
    fp.write(struct.pack('<H', 0))        # delay
    fp.write('\x00')                      # transparent color index
    fp.write('\x00')                      # block end  
  # image block
  fp.write('\x2c')                      # separator
  fp.write(struct.pack("<HH", 0, 0))    # position
  fp.write(struct.pack("<HH", w, h))    # size again
  fp.write('\x00')                      # flags ()
  fp.write('\x08')                      # "LZW Minimum Code Size" ?
  fp.write(im.tostring("gif", "L"))     # data
  fp.write('\x00')                      # block terminator
  fp.write('\x3b')                      # gif trailer
  return

if __name__ == "__main__":
  data = [ [ 1, 1, 1, 1 ],
           [ 0, 1, 0, 1 ],
           [ 0, 0, 1, 1 ],
           [ 0, 0, 0, 1 ] ]
  fp = file("test.gif", "wb")
  makegifbw(data, fp, True)
  fp.close()
