img.py

'''\
Images.

classes:
    Point       (object)
    Img         (object)
    Chart       (Img)
    XYChart     (Chart)

functions:
    dispatch(cmd,[args])    - Module Command Dispatch
    doit()                  - Default function

Developer@Sonnack.com
May 2012
'''
####################################################################################################
from sys import stdoutstderrargv
from datetime import datetimedelta
from os import path
import mathrandom
import ImageImageDrawImageFont
from colors import *
####################################################################################################
Log = stderr

fBox = lambda xy,d: (xy[0]-int(d/2), xy[1]-int(d/2), xy[0]+int(d/2), xy[1]+int(d/2))

tAdd = lambda t1,t2: tuple(map(lambda x1,x2: x1+x2t1t2))
tSub = lambda t1,t2: tuple(map(lambda x1,x2: x1-x2t1t2))

random.seed()

fntHelvR08 = 'C:\\Python27\\Lib\\site-packages\\pilfonts\\helvR08.pil'
fntHelvR10 = 'C:\\Python27\\Lib\\site-packages\\pilfonts\\helvR10.pil'
fntHelvB08 = 'C:\\Python27\\Lib\\site-packages\\pilfonts\\helvB08.pil'
fntHelvB10 = 'C:\\Python27\\Lib\\site-packages\\pilfonts\\helvB10.pil'


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class Point (object):
    '''Point class.'''
    def __init__ (selfx=0y=0):
        '''Create new Point instance.'''
        self.x = x
        self.y = y

    def __str__ (self):
        '''String version (a comma-separated number pair).'''
        return '%f, %f' % (self.xself.y)

    def __repr__ (self):
        '''Canonical representation (a tuple).'''
        return (self.xself.y)


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class PieGraph (object):
    def __init__ (selfdata):
        '''New PieGraph instance.  {data=pie slice sizes}'''
        tot = reduce(lambda acc,x: acc + float(x), data0.0)
        print 'tot: ',tot
        self.pieces = map(lambda x: [xfloat(x)/tot0,0], data)
        a = 0
        for pc in self.pieces:
            pc[2] = a
            a = a + int(pc[1] * 360.0)
            pc[3] = a

    def draw (selfimgxyradius):
        '''New PieGraph instance.  {img=Img instance, xy=location tuple}'''
        bx = fBox(xyradius)
        print 'box: ',bx
        for pc in self.pieces:
            c = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
            img.draw.pieslice(bxpc[2],pc[3], fill=coutline=ColorBlack)
            print pc
        return self


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class Img (object):
    '''\
Image base class.

This simple class just encapsulates the Image API in a helper object.

Note that images created with this class automatically have a three-pixel
border around them.

usage:
        dims = (640, 480)
        im = Img(dims)

'''
    def __init__ (selfdimsbg=ColorWhite):
        '''Create new Img instance with given dimensions.'''
        self.dims = dims
        self.im = Image.new('RGB'dimsbg)
        self.draw = ImageDraw.Draw(self.im)
        self.draw.rectangle((0,0)+(self.dims[0]-1,self.dims[1]-1), outline=ColorBlack)
        self.draw.rectangle((1,1)+(self.dims[0]-2,self.dims[1]-2), outline=ColorDarkGray)
        self.draw.rectangle((2,2)+(self.dims[0]-3,self.dims[1]-3), outline=ColorGray)

    def get (selfxy):
        if not (isinstance(xy,tupleor isinstance(xy,list)):
            raise TypeError,('Index must be a tuple or list! (not a "%s")' % type(xy).__name__)
        if not (len(xy) == 2):
            raise TypeError,('Index must have two coordinates! (not %d)' % len(xy))
        if (self.dims[0] <= xy[0]) or (self.dims[1] < xy[1]):
            raise IndexError,('Index out of bounds! %s' % str(xy))
        return self.im.getpixel(xy)

    def circle (selfxyradiusfgbg):
        '''Draw a circle.'''
        ulc = (xy[0]-radiusxy[1]-radius)
        lrc = (xy[0]+radiusxy[1]+radius)
        self.draw.ellipse([ulclrc], outline=fgfill=bg)
        return self

    def show (self):
        '''Display image in default viewer.'''
        self.im.show()
        return self

    def save (selffnmode='PNG'):
        '''Save image as a file.'''
        self.im.save(fnmode)
        return self

    def __str__ (self):
        '''String version: format, size, mode.'''
        s = '%s (%d,%d) %s'
        t = (self.im.formatself.im.size[0], self.im.size[1], self.im.mode)
        return s % t

    def __repr__ (self):
        '''Canonical representation (JSON-like string).'''
        s = '{Img:{format:"%s", size:%s, mode:"%s", addr:%x}}'
        t = (self.im.formatstr(self.im.size), self.im.modeself.__hash__())
        return s % t


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class Chart (Img):
    '''\
Chart Image base class.

This class encapsulates the idea of a plot area on the image.
There is a title centered across the top of the plot area.
There is an X-axis along the bottom and a Y-axis along the left.

The values provided for the axes are evenly spaced along the plot area sides.
The values may be strings or numbers (which are converted to strings).

Note that the Y-axis text is painted from top-to-bottom, so the first
value provided in the list goes at the top and the last on goes at the
axis bottom.

Currently the client must call the .make() method to generate the
plot area, title and axes. If not called, the chart just has its
gray background (making it similar to a plain image).

Clients use the .plot_ulc, .plot_lrc and .plot_dim properties to draw
directly on the chart plot area. Each property is a (x,y) tuple. The
first two define the corners; the last one defines the plot area size.

usage:
        ttl = 'My Awesome Chart'
        sz  = (640, 480)
        xa  = [0, 90, 180, 270, 360]
        ya  = [+1, 0, -1]
        im = Img(sz, ttl, xa,ya)
        im.make()

'''
    def __init__ (selfdimstitle=Nonex_axis=[], y_axis=[], bg=ColorWhite):
        '''Create new Chart instance.'''
        super(Chart,self).__init__(dimsColorFaintGray)
        self.font_axis = ImageFont.load(fntHelvR08)
        self.font_title = ImageFont.load(fntHelvB10)
        self.margin = (9,4,12,9)
        self.title = title
        self.x_axis = x_axis
        self.y_axis = y_axis
        self.plot_bg = bg
        # Title box...
        self.title_box = self.draw.textsize(self.titlefont=self.font_title)
        # X-axis box...
        self.x_axis_box = self._calc_axis_text_size(self.x_axis)
        # Y-axis box...
        self.y_axis_box = self._calc_axis_text_size(self.y_axis)
        # Plot box...
        self.plot_ulc = (self.margin[0] + self.y_axis_box[0], self.margin[1] + self.title_box[1])
        self.plot_lrc = (dims[0]-self.margin[2], dims[1]-(self.margin[3] + self.x_axis_box[1]))
        self.plot_dim = tSub(self.plot_lrcself.plot_ulc)
        #
        self.x_axis_ulc = (self.plot_ulc[0], self.plot_lrc[1])
        self.x_axis_box = (self.plot_dim[0], self.x_axis_box[1])
        #
        self.y_axis_ulc = (self.margin[0]    , self.plot_ulc[1])
        self.y_axis_box = (self.y_axis_box[0], self.plot_dim[1])
        #
        self.title_ulc = (self.plot_ulc[0] + (int(self.plot_dim[0] / 2) - int(self.title_box[0] / 2)), self.margin[1])
        print "plot:"self.plot_ulcself.plot_lrc

    def make (self):
        '''Make the chart.'''
        self._draw_plot_area()
        self._draw_x_axis()
        self._draw_y_axis()
        self.draw.text(self.title_ulcself.titlefont=self.font_titlefill=ColorBlack)
        return self

    def _draw_plot_area (self):
        '''private:Draw Plot Area.'''
        self.draw.rectangle([self.plot_ulcself.plot_lrc], outline=ColorBlackfill=self.plot_bg)
        return self

    def _draw_x_axis (self):
        '''private:Draw X-Axis.'''
        if not self.x_axis:
            return self
        lrc = tAdd(self.x_axis_ulcself.x_axis_box)
        n = len(self.x_axis)
        px = int(self.x_axis_box[0] / (n-1)) if 1 < n else 0
        for ix,t in enumerate(self.x_axis):
            s = str(t)
            sz = self.draw.textsize(sfont=self.font_axis)
            if ix == 0:
                # First one left justifies...
                ulc = self.x_axis_ulc
            elif ix == (n - 1):
                # Last one right justifies...
                ulc = tSub(lrcsz)
            else:
                # Others center...
                ulc = ((self.x_axis_ulc[0] + (ix * px)) - int(sz[0]/2), self.x_axis_ulc[1])
            self.draw.text(ulcsfont=self.font_axisfill=ColorBlack)
        return self

    def _draw_y_axis (self):
        '''private:Draw Y-Axis.'''
        if not self.y_axis:
            return self
        lrc = tAdd(self.y_axis_ulcself.y_axis_box)
        n = len(self.y_axis)
        py = int(self.y_axis_box[1] / (n-1)) if 1 < n else 0
        for ix,t in enumerate(self.y_axis):
            s = str(t)
            sz = self.draw.textsize(sfont=self.font_axis)
            if ix == 0:
                # First one top justifies...
                ulc = (lrc[0]-sz[0], self.y_axis_ulc[1])
            elif ix == (n - 1):
                # Last one bottom justifies...
                ulc = tSub(lrcsz)
            else:
                # Others center...
                ulc = (lrc[0]-sz[0], (self.y_axis_ulc[1] + (ix * py)) - int(sz[1]/2))
            self.draw.text(ulcsfont=self.font_axisfill=ColorBlack)
        return self

    def _calc_axis_text_size (selfaxis):
        '''private:Calculate Axis Text Size.'''
        rv = [0,0]
        for t in axis:
            s = str(t)
            sz = self.draw.textsize(sfont=self.font_axis)
            if rv[0] < sz[0]:
                rv[0] = sz[0]
            if rv[1] < sz[1]:
                rv[1] = sz[1]
        return tuple(rv)

    def __repr__ (self):
        '''Canonical representation (JSON-like string).'''
        s = '{Chart:{parent:%s, ulc:%s, lrc:%s, plot:%s, title:"%s"}}'
        t = (super(Chart,self).__repr__(), str(self.plot_ulc), str(self.plot_lrc), str(self.plot_dim), self.title)
        return s % t


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class XYChart (Chart):
    '''\
XY Chart Image class.

This class adds the capability to draw in the plot area.

usage:
        ttl = 'My Awesome Chart'
        sz  = (640, 480)
        pz  = (360, 2)
        xa  = [0, 90, 180, 270, 360]
        ya  = [+1, 0, -1]
        xg  = (90, 30)
        yg  = (1, )
        im = XYChart(sz, ttl, xa,ya, xg,yg)
        im.make()

'''
    def __init__ (selfdimsscaletitle=Nonex_axis=[], y_axis=[], x_grid=(), y_grid=(), bg=ColorWhite):
        '''Create new Chart. {dims=(x,y), scale=(x,y), _axis=[], _grid=(max,min)}'''
        super(XYChart,self).__init__(dimstitlex_axisy_axisbg)
        self.scale = scale
        self.x_grid = x_grid
        self.y_grid = y_grid
        #
        self.factor = (self.plot_dim[0] / float(self.scale[0]), self.plot_dim[1] / float(self.scale[1]))
        print "factor:"self.factor

    def make (self):
        '''Make the Chart.'''
        super(XYChart,self).make()
        self._draw_x_grid()
        self._draw_y_grid()
        return self

    def plot (selfdatacolor=ColorRedwidth=1):
        '''Draw the Chart. {data=[xy1,xy2,..]}'''
        pdata = map(lambda t: (self.fx(t[0]), self.fy(t[1])), data)
        self.draw.line(pdatafill=colorwidth=width)
        return self

    def plot_vlines (selfdatacolor=ColorRedwidth=1):
        '''Draw the Chart using vertical lines.'''
        yb = self.fy(0)
        pdata = map(lambda t: (self.fx(t[0]), self.fy(t[1])), data)
        for pt in pdata:
            self.draw.line([(pt[0],yb), pt], fill=colorwidth=width)

    def fx (selfx):
        '''Factor X.'''
        return self.plot_ulc[0] + (x * self.factor[0])

    def fy (selfy):
        '''Factor Y.'''
        return self.plot_lrc[1] - (y * self.factor[1])

    def _draw_x_grid (self):
        '''private:Draw X Grid.'''
        if not self.x_grid:
            return self
        if 1 < len(self.x_grid):
            x = self.x_grid[1]
            while x < self.scale[0]:
                px = self.fx(x)
                p0 = (pxself.plot_ulc[1]+1)
                p1 = (pxself.plot_lrc[1]-1)
                self.draw.line([p0p1], fill=ColorGray200)
                x = x + self.x_grid[1]
        if 0 < len(self.x_grid):
            x = self.x_grid[0]
            while x < self.scale[0]:
                px = self.fx(x)
                p0 = (pxself.plot_ulc[1]+1)
                p1 = (pxself.plot_lrc[1]-1)
                self.draw.line([p0p1], fill=ColorGray100)
                x = x + self.x_grid[0]
        return self

    def _draw_y_grid (self):
        '''private:Draw Y Grid.'''
        if not self.y_grid:
            return self
        if 1 < len(self.y_grid):
            y = self.y_grid[1]
            while y < self.scale[1]:
                py = self.fy(y)
                p0 = (self.plot_ulc[0]+1py)
                p1 = (self.plot_lrc[0]-1py)
                self.draw.line([p0p1], fill=ColorGray200)
                y = y + self.y_grid[1]
        if 0 < len(self.y_grid):
            y = self.y_grid[0]
            while y < self.scale[1]:
                py = self.fy(y)
                p0 = (self.plot_ulc[0]+1py)
                p1 = (self.plot_lrc[0]-1py)
                self.draw.line([p0p1], fill=ColorGray100)
                y = y + self.y_grid[0]
        return self

    def __repr__ (self):
        '''Canonical representation (JSON-like string).'''
        s = '{XYChart:{parent:%s, scale:%s, xgrid:%s, ygrid:%s}}'
        t = (super(XYChart,self).__repr__(), str(self.scale), str(self.x_grid), str(self.y_grid))
        return s % t


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class BarChart (Chart):
    '''Bar Chart Image class.'''
    def __init__ (selfdimsy_scaletitle=Nonex_axis=[], y_axis=[], y_grid=(), bg=ColorWhite):
        '''Create new Chart. {dims=(x,y), _axis=[], y_scale=f, y_grid=(max,min)}'''
        super(BarChart,self).__init__(dimstitlex_axisy_axisbg)
        self.y_scale = y_scale
        self.y_grid = y_grid
        self.y_factor = float(self.plot_dim[1]) / float(y_scale)
        print "factor:"self.y_factor

    def make (self):
        super(BarChart,self).make()
        self._draw_y_grid()
        return self

    def fy (selfy):
        return self.plot_lrc[1] - (y * self.y_factor)

    def _draw_y_grid (self):
        if not self.y_grid:
            return self
        if 1 < len(self.y_grid):
            for y in range(self.y_grid[1], self.y_scaleself.y_grid[1]):
                py = self.fy(y)
                p0 = (self.plot_ulc[0]+1py)
                p1 = (self.plot_lrc[0]-1py)
                self.draw.line([p0p1], fill=(239,239,239))
        if 0 < len(self.y_grid):
            for y in range(self.y_grid[0], self.y_scaleself.y_grid[0]):
                py = self.fy(y)
                p0 = (self.plot_ulc[0]+1py)
                p1 = (self.plot_lrc[0]-1py)
                self.draw.line([p0p1], fill=(191,191,191))
        return self

    def __repr__ (self):
        s = '{BarChart:{parent:%s, ygrid:%s}}'
        t = (super(BarChart,self).__repr__(), str(self.y_grid))
        return s % t



##================================================================================================##
def demo0 (*args):
    sz = (640480)
    pz = (36020)
    xa = [090180270360]
    ya = ['+1'0'-1']
    xg = (45, )
    yg = (51)
    im = XYChart(szpz'Sine and Cosine'xa,yaxg,yg)

    im.make()

    dda = [(x10 + (9 * math.sin(math.radians(float(x))))) for x in range(0,360,5)]
    ddb = [(x10 + (9 * math.cos(math.radians(float(x))))) for x in range(0,360,5)]

    im.plot(ddaColorRed)
    im.plot(ddbColorBlue)

    # Save & Show...
    im.save('demo0.png')
    im.show()
    return im


##================================================================================================##
def demo1 (*args):
    fn = 'demo1.png'
    sz = (640480)
    c1 = ( 30,  30)
    c2 = (610,  30)
    c3 = (610450)
    c4 = ( 30450)
    bx = (100100sz[0]-100sz[1]-100)

    font0 = ImageFont.load(fntHelvR08)
    font1 = ImageFont.load(fntHelvB08)
    font2 = ImageFont.load(fntHelvB10)

    im = Image.new('RGB'szColorWhite)
    draw = ImageDraw.Draw(im)
    try:
        # Draw grid...
        c = (223223255)
        for x in range(0sz[0], 12):
            draw.line([(x,0), (x,sz[1]-1)], fill=c)
        for y in range(0sz[1], 12):
            draw.line([(0,y), (sz[0]-1,y)], fill=c)

        # Draw corner circles...
        draw.ellipse(fBox(c1,40), fill=ColorRed   , outline=ColorBlack)
        draw.ellipse(fBox(c2,40), fill=ColorYellowoutline=ColorBlack)
        draw.ellipse(fBox(c3,40), fill=ColorGreen , outline=ColorBlack)
        draw.ellipse(fBox(c4,40), fill=ColorBlue  , outline=ColorBlack)

        # Draw "plot" area...
        draw.rectangle(bxfill=ColorLightGrayoutline=ColorBlack)

        draw.text((bx[0]+29,bx[1]+3), 'American League'font=font2fill=(0,0,0))
        draw.text((bx[0]+225,bx[1]+3), 'National League'font=font2fill=(0,0,0))

        draw.text((bx[0]+17,bx[1]+20), 'West'font=font1fill=(0,0,0))
        draw.text((bx[0]+65,bx[1]+20), 'Central'font=font1fill=(0,0,0))
        draw.text((bx[0]+128,bx[1]+20), 'East'font=font1fill=(0,0,0))

        draw.text((bx[0]+213,bx[1]+20), 'West'font=font1fill=(0,0,0))
        draw.text((bx[0]+261,bx[1]+20), 'Central'font=font1fill=(0,0,0))
        draw.text((bx[0]+324,bx[1]+20), 'East'font=font1fill=(0,0,0))

        # AL - West
        x = bx[0] + 12
        y = bx[1] + 36
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_sea_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_oak_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_ana_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_tex_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_hou_36x32.png")
        im.paste(icon, (x,y))

        # AL - Central
        x = x + int(icon.size[0] * 1.5)
        y = bx[1] + 36
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_min_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_cws_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_det_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_cle_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_kc_36x32.png")
        im.paste(icon, (x,y))

        # AL - East
        x = x + int(icon.size[0] * 1.5)
        y = bx[1] + 36
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_tor_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_bos_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_nyy_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_bal_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_tb_36x32.png")
        im.paste(icon, (x,y))

        # NL - West
        x = x + int(icon.size[0] * 2.5)
        y = bx[1] + 36
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_sf_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_la_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_sd_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_ari_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_col_36x32.png")
        im.paste(icon, (x,y))

        # NL - Central
        x = x + int(icon.size[0] * 1.5)
        y = bx[1] + 36
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_mil_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_chc_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_pit_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_cin_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_stl_36x32.png")
        im.paste(icon, (x,y))

        # NL - East
        x = x + int(icon.size[0] * 1.5)
        y = bx[1] + 36
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_nym_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_phi_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_was_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_atl_36x32.png")
        im.paste(icon, (x,y))
        y = y + icon.size[1]
        icon = Image.open(r"C:\Users\Chris\Pictures\BB\icons\im_logo_mia_36x32.png")
        im.paste(icon, (x,y))

        draw.arc(fBox((sz[0]-1sz[1]-1), 12), 190,260fill=ColorDarkBlue)
        draw.arc(fBox((sz[0]-1sz[1]-1), 15), 190,260fill=ColorDarkBlue)
        draw.arc(fBox((sz[0]-1sz[1]-1), 19), 190,260fill=ColorDarkBlue)
        draw.arc(fBox((sz[0]-1sz[1]-1), 24), 190,260fill=ColorDarkBlue)

        draw.rectangle((0,0sz[0]-1,sz[1]-1), outline=ColorBlack)
        draw.rectangle((1,1sz[0]-2,sz[1]-2), outline=ColorDarkGray)
        draw.rectangle((2,2sz[0]-3,sz[1]-3), outline=ColorGray)
        draw.rectangle((3,3sz[0]-4,sz[1]-4), outline=ColorLightGray)

        s = 'Chris@Sonnack.com'
        b = draw.textsize(sfont=font1)
        x = sz[0] - (b[0]+50)
        y = sz[1] - (b[1]+5)
        draw.text((x,y), sfont=font1fill=(127,127,127))

    except Exception as e:
        print >> stderre
        return e
    finally:
        del draw
        im.save(fn'PNG')

    im.show()
    return im


##================================================================================================##
ChartMax  = (164120)
ChartMul  = (21)
ChartSize = (ChartMax[0] * ChartMul[0], (1 + (2 * ChartMax[1])) * ChartMul[1])
ChartDims = (ChartSize[0]+30ChartSize[1]+30)
ChartULC  = (2010)
ChartLRC  = (ChartULC[0]+ChartSize[0], ChartULC[1]+ChartSize[1])
ChartX    = lambda x: ChartULC[0] + (2 * int(x))
ChartY    = lambda y: (ChartULC[1] + ChartMax[1]) - int(y)
##------------------------------------------------------------------------------------------------##
def demo2 (*args):
    '''\
Generate a Chart.

'''
    fn = 'demo2.png'
    x0 = ChartX(1)
    x1 = ChartX(ChartMax[0]-1)
    zy = ChartY(0)

    im = Image.new('RGB'ChartDimsColorWhite)
    draw = ImageDraw.Draw(im)
    try:
        # Draw border...
        draw.rectangle((0,0)+(ChartDims[0]-1,ChartDims[1]-1), outline=ColorBlack)
        draw.rectangle((2,2)+(ChartDims[0]-3,ChartDims[1]-3), outline=ColorDarkGray)

        # Draw plot area...
        draw.rectangle(ChartULC+ChartLRCfill=ColorLightGrayoutline=ColorBlack)

        m = int(20)
        f = ChartMax[1] / float(m)

        # Draw grid lines...
        for n in range(1m):
            yp = ChartY(f * +n)
            yn = ChartY(f * -n)
            c = ColorGray if n % 10 else ColorDarkGray
            draw.line([(x0,yp), (x1,yp)], width=1fill=c)
            draw.line([(x0,yn), (x1,yn)], width=1fill=c)

        # Draw Y-Zero Axis...
        draw.line([(x0,zy), (x1,zy)], width=1fill=ColorBlack)

        # Draw test pattern (sine wave)...
        for x in range(ChartMax[0]-1):
            px = ChartX(1+x)
            py = ChartY(int(80 * math.sin(math.radians((x/float(ChartMax[0])) * 360.0))))
            draw.point((pxpy), fill=ColorRed)

    except Exception as e:
        print >> stderre
        return e
    finally:
        del draw
        im.save(fn'PNG')

    im.show()
    return im


##================================================================================================##
class GameCounter (object):
    def __init__ (self):
        self.games = 0
    def get (self):
        if random.random() < 0.5:
            self.games = self.games + 1
        return self.games

##------------------------------------------------------------------------------------------------##
def demo3 (*args):
    fn = 'demo3.png'
    sz = (640480)
    pz = (162100)
    xa = [0275481108135162]
    ya = [1007550250]
    xg = (273)
    yg = (255)
    im = XYChart(szpz'Twins Team BA - 2013'xa,yaxg,yg)

    im.make()

    gc = GameCounter()
    dd = [(0,0)] + [(1+xgc.get()) for x in range(81)]
    im.plot(ddColorRed)

    gc = GameCounter()
    dd = [(0,0)] + [(1+xgc.get()) for x in range(162)]
    im.plot(ddColorBlue)

    gc = GameCounter()
    dd = [(0,0)] + [(1+xgc.get()) for x in range(162)]
    im.plot(dd, (0,127,0))

    # Save & Show...
    im.save(fn)
    im.show()
    return im

##================================================================================================##
def demo4 (*args):
    sz = (640480)
    pz = (100100)
    xa = [0.0, .25, .50, .751.0]
    ya = ['1.0', .50'0.0']
    xg = (255)
    yg = (255)
    F = lambda x: 100 * ((float(100-x)/100.0) ** 2)

    im = XYChart(szpz'Curve'xa,yaxg,yg)

    im.make()

    dda = [(xF(x)) for x in range(100)]

    im.plot(ddaColorRed)

    # Save & Show...
    im.save('demo4.png')
    im.show()
    return im



##================================================================================================##
## DISPATCH...
##================================================================================================##
def dispatch (cmd, *args):
    '''\
Dispatch Command.

usage:
    module_name {command} {arguments}

commands:
    demo0           - Demo #0 - Img class test
    demo1           - Demo #1 - Hello, World!
    demo2           - Demo #2 - A Chart
    main            - Default function

'''
    print 'command:'cmd
    if cmd == 'demo0':
        return demo0(*args)
    if cmd == 'demo1':
        return demo1(*args)
    if cmd == 'demo2':
        return demo2(*args)
    if cmd == 'demo3':
        return demo3(*args)
    if cmd == 'demo4':
        return demo4(*args)
    if (len(cmd) == 0or (cmd == 'main'or (cmd == 'default'):
        return demo0(*args)
    return None

####################################################################################################
if __name__ == '__main__':
    print 'autorun:'argv[0]
    cmnd = argv[1if 1 < len(argvelse 'demo4'
    args = argv[2:if 2 < len(argvelse []
    obj = dispatch(cmnd, *args)
    if obj:
        print type(obj)

####################################################################################################
'''eof'''