#!/usr/local/bin/python2.3

# panner.py -- a program for displaying panagraphic stereo images
# by: John Zelle (Wartburg College)

"""
panner [-s scale] leftImage rightImage
  or
panner [-s scale] anaglyphImage

panner is a program for displaying paired images for stereo
viewing. It loads left and right image files specified on the command
line and displays them side-by-side in a full-screen window sized to
display each image in the center of the respective screens of a
desktop extended over a dual-head display. If only a single file is
provided, it is treated as a red-blue or red-cyan anaglyph. The image
is separated into left and right images for passive (black and white)
stereo viewing.

Note: This application can be quite memory intensive. If the input images are
large, the -s option can be used to reduce the full-image size. For example,
    panner -s 0.5 left.tif right.tif
cuts the full-image size in half.

Key-bindings:
    arrow keys    pan left, right, up, and down
    z             zoom out (image gets smaller)
    Z             zoom in (image gets larger)
    q             quit
"""


import Tkinter as tk
import PIL.Image as Image
import PIL.ImageTk

class LRViewer(tk.Frame):

    def __init__(self, master, leftImage, rightImage, width=1024, height=768):
        tk.Frame.__init__(self, master=master, bg="black")
        self.leftCanvas = tk.Canvas(self, width=width, height=height,
                                    xscrollincrement=1, yscrollincrement=1,
                                    highlightthickness=0, bg="black")
        self.leftCanvas.pack(side="left")
        self.rightCanvas = tk.Canvas(self, width=width, height=height,
                                     xscrollincrement=1, yscrollincrement=1,
                                     highlightthickness=0, bg="black")
        self.rightCanvas.pack(side="right")
        self.reduce = 1.0
        self.leftimg=leftImage
        self.rightimg=rightImage
        self.xoffset = 0
        self.yoffset = 0
        self.show()

    def show(self):
        factor = self.reduce
        x,y = self.leftimg.size
        x = int(round(x*factor))
        y = int(round(y*factor))

        left = self.leftview = PIL.ImageTk.PhotoImage(self.leftimg.resize((x,y)))
        right = self.rightview = PIL.ImageTk.PhotoImage(self.rightimg.resize((x,y)))
        xc = int(self.leftCanvas.cget("width"))/2 +(1-factor)*self.xoffset
        yc = int(self.leftCanvas.cget("height"))/2+(1-factor)*self.yoffset
        self.leftCanvas.create_image(xc,yc, image=left)
        self.rightCanvas.create_image(xc,yc,image=right)

    def panx(self, dx):
        l,r = self.leftCanvas, self.rightCanvas
        l.xview_scroll(dx,tk.UNITS)
        r.xview_scroll(dx,tk.UNITS)
        self.xoffset += dx

    def pany(self, dy):
        l,r = self.leftCanvas, self.rightCanvas
        l.yview_scroll(dy, tk.UNITS)
        r.yview_scroll(dy,tk.UNITS)
        self.yoffset += dy

    def zoom(self, factor):
        self.reduce = min(self.reduce * factor, 1.0)
        self.show()

def deglyph(file):
    img = Image.open(file)
    if img.mode != 'RGB':
        img = img.convert('RGB')
    r,g,b = img.split()
    left = Image.merge("RGB",(r,r,r))
    right = Image.merge("RGB",(b,b,b))
    return left,right


if __name__ == '__main__':
    from getopt import getopt
    import sys

    if len(sys.argv) < 2 or '-h' in sys.argv or '--help' in sys.argv:
        print __doc__
        sys.exit(1)

    # parse the filenames and optional scale (-s argument)
    try:
        opts, files = getopt(sys.argv[1:],"s:")
    except Exception, e:
        print e
        sys.exit(1)

    # set scale factor
    if opts:
        scale = float(opts[0][1])
    else:
        scale = 1.0

    # get left and right image files    
    if len(files) == 1:
        left, right = deglyph(files[0])
    else:
        left = Image.open(files[0])
        right = Image.open(files[1])
    x,y = left.size
    x = int(scale*x)
    y = int(scale*y)
    left = left.resize((x,y))
    right = right.resize((x,y))

    # create the main application window and hide it
    master = tk.Tk()
    master.withdraw()

    # create viewing window
    win = tk.Toplevel(master)
    w = master.winfo_screenwidth()/2
    h = master.winfo_screenheight()
    viewer = LRViewer(win, left, right, width=w, height=h)
    viewer.pack()
    win.overrideredirect(1) # make it a fullscreen (undecorated) window

    # set up key bindings for master window
    master.bind("<Key-q>", lambda e, w=win: w.quit())
    master.bind("<Key-Right>", lambda e, v=viewer: v.panx(10))
    master.bind("<Key-Left>", lambda e, v=viewer: v.panx(-10))
    master.bind("<Key-Up>", lambda e, v=viewer: v.pany(-10))
    master.bind("<Key-Down>", lambda e, v=viewer: v.pany(10))
    master.bind("<Key-z>", lambda e, v=viewer: v.zoom(.9))
    master.bind("<Key-Z>", lambda e, v=viewer: v.zoom(1.1))

    # bring master back (under the viewing window) and process keypresses
    master.deiconify()
    master.mainloop()




        
