#!/usr/bin/env python2.4

# turn a bunch of numbers into coloured boxes in a ppm file.
# Ian Wienand <ianw@ieee.org>
# (C) 2006 - Released to public domain

import sys, string
from optparse import OptionParser

class Pixel:
    '''An RGB element'''
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b

    def __str__(self):
        return "%3d %3d %3d " % (self.r, self.g, self.b)

# box is made up of rows of pixels
#  Box =
#  [
#    [ Pixel, Pixel, Pixel ],
#    [ Pixel, Pixel, Pixel ]
#    ...
#  ]
class Box:
    '''A box simply contains rows of pixels'''
    def __init__(self):
        self.rows = []
        self.height = 0
    def add_row(self, row):
        self.rows.append(row)
        self.height += 1

    def get_row(self, row):
        s = ""
        for p in self.rows[row]:
            s += str(p)
        return s

    def __str__(self):
        s = ""
        for r in self.rows:
            for p in r:
                s += str(p)
            s += '\n'
        return s

# PPM = [ Box, Box, Box, Box, ..., Box ]
class PPM:
    '''
    create a Portable Pixel Map from the input
    - inlist : list of numbers
    - boxheight,boxwidth : height and width of coloured boxes in output
    - outputwidth : number of boxes wide the image should be
    '''
    def __init__(self, inlist, boxheight, boxwidth, outputwidth):
        self.boxheight = boxheight
        self.boxwidth = boxwidth
        self.total_boxes = len(inlist)
        # pad output with zeros
        if (self.total_boxes != outputwidth):
            inlist.extend([0 for x in range(0, outputwidth - self.total_boxes)])
            self.total_boxes = len(inlist)
        #number of boxes wide for output
        self.outputwidth = outputwidth
        #total width, in pixels
        self.total_width = (boxwidth) * outputwidth
        #total height, in pixels
        self.total_height = boxheight * (self.total_boxes/outputwidth);
        self.boxes = []

        # go through the input file, and make one box for each
        # incoming pixel
        for c in inlist:
            if (int(c) == 0):
                color = Pixel(255,255,255)
            else:
                color  = Pixel(255 - int(float(int(c))/10 * 255), 0, 0)
            box = Box()
            for h in range(0, boxheight):
                row = []
                for w in range(0, boxwidth):
                    row.append(color)
                box.add_row(row)
            self.boxes.append(box)

    def __str__(self):
        #ppm header
        image = "P3\n"
        image += "%d %d\n" % (self.total_width, self.total_height)
        image += "# autogenerated by numbers2ppm\n"
        image += "255\n"

        n = 0
        # our input is one giant list of boxes
        while n < self.total_boxes:
            # take a row worth of boxes into 'boxes'
            boxes = self.boxes[n:n+self.outputwidth]
            for r in range(0, self.boxheight):
                therow=""
                # for each pixel line in this row, get what the box
                # wants to colour it as
                for b in boxes:
                    therow += b.get_row(r)
                image += therow + "\n"

            n += self.outputwidth
        return image

def main():
    usage = "numbers2ppm.py [-W width] [-H height] [-c count] input"
    
    parser = OptionParser(usage, version=".1")

    parser.add_option("-W", "--width", dest="width", action="store", type="int",
                      default=5, help="Width of output boxes")
    parser.add_option("-H", "--height", dest="height", action="store", type="int",
                      default=5, help="Height of output boxes")
    parser.add_option("-c", "--count", dest="count", action="store", type="int",
                      default=50, help="Number of boxes wide for image")
    
    (options, args) = parser.parse_args()

    if (len(args) != 1):
        parser.print_help()
        sys.exit(1)
    
    instring = string.join(open(args[0]).readlines()).strip()
    #convert to a list
    inlist = [x for x in instring]
    p = PPM(inlist, options.height, options.width, options.count)

    print p

if __name__ == "__main__":
    main()
