#!/usr/bin/env python
# Takes an ascii drawing and fills it with letters
# Natan 'whatah' Zohar
import math
import string
import Image
import ImageFilter
import getopt
import sys

VERSION="0.01"
def imgToAscii(file, charw, invert):
    im = Image.open(file)
    w, h = im.size
    factor = charw / float(w)
    w = int(w * factor)
    h = int(h * factor)

    im = im.resize((w,h))
    im = im.filter(ImageFilter.SHARPEN)
    im = im.convert('1')
    
    data = list(im.getdata())
    
    lines = []
    if invert:
        cw = 'G'
        cb = ' '
    else:
        cw = ' '
        cb = 'G'

    for x in range(len(data) / w):
        line = ""
        for pixel in data[x*w:x*w+w]: 
            if pixel == 255:
                line += cw
            else:
                line +=  cb
        lines.append(line)

    return lines

def fillAscii(lines, fill):
    letters = len(fill)
    count = 0
    for line in lines:
        for letter in line:
            if letter.isalnum():
                count += 1

    if letters < count:
        m = 1
        fill *= int(math.ceil(float(count) / float(letters)))
    else:
        m = int(float(letters) / float(count))
        m = int(math.sqrt(m))


    ss = []

    # Generate an array of what we will be placing inside the image (strings of size m)
    for x in range(count*m):
        st = fill[x*m:x*m+m]
        if len(st) < m:
            st += ' ' * (m - len(st))
        ss.append(st)
        
    ret = ""
   
    it = ss.__iter__()
    # position the elements of ss inside the image
    for line in lines:
        for i in range(m):
            for letter in line:
                if not letter.isalnum():
                    ret += ' ' * m
                    continue
                ret += it.next()
            ret += '\n'
    return ret

def usage():
    print "usage: filler.py [OPTION]\nVersion %s \n\
    -f, --fill=FILE     create ascii image using FILE's text (required) \n\
    -h, --help          display this help and exit \n\
    -i, --invert        invert the layout of the text \n\
    -m, --map=IMAGE     map the text in the shape of IMAGE (required) \n\
    -s, --no-squish     keep all whitespace from fill intact \n\
    -w, --width=INT     width in chars to resize image to \
    " % VERSION

if __name__ == "__main__":
    try:
        opt, args = getopt.getopt(sys.argv[1:], "hisf:m:w:", ["help", "invert", "no-squish", "fill=", "map=", "width="])
    except getopt.GetoptError:
        usage()
        sys.exit(0)
    
    fillfile = None
    imagefile = None
    charw = 80
    invert = False
    squish = True

    for o, a in opt:
        if o in ('-h', '--help'):
            usage()
            sys.exit(0)
        if o in ('-s', '--no-squish'):
            squish = False
        if o in ('-f', '--fill'):
            fillfile = open(a)
        if o in ('-m', '--map'):
            imagefile = a
        if o in ('-w', '--width'):
            charw = int(a)
        if o in ('-i', '--invert'):
            invert = True

    if imagefile == None or fillfile == None:
        usage()
        sys.exit(0)
        
        
        
    
    s = fillfile.read()
    if squish:
        t = string.maketrans('', '')
        s = s.translate(t, string.whitespace)
    lines = imgToAscii(imagefile, charw, invert)
    print fillAscii(lines, s)
