#!/usr/bin/python2 #test-pds-tk.py - a Bippy test script - 22 Oct. 2004 #an original script written by Bill Allen for Python 2+ #this script has no price, limitations, or warranty - use at your own risk """ This is a simple Tkinter GUI-interface script written for the sole purpose of testing modules for PDS file handling. It displays PDS image files at original dimensions and (by default) saves an equalized GIF copy. To use this script, place it and its modules in a folder immediately _below_ a folder with PDS-format image files (usually .img, sometimes .pds). Click on this script (or a desktop shortcut to it) to cycle through all such files in that upper folder, launching and closing each file window in turn. (If not found, the script will create its own subordinate \temp folder.) The suggested folder structure on whatever hard drive is... C:\bippy <- put PDS files here (GIF & RAW files will output here, too) |-python <- put Python files (this file & its modules) here |-temp <- check occasionally to delete orphaned .tmp files This script can be run from within Python IDLE but will only run once, and not again until all Python windows have been closed and Python relaunched. This is due to a Tkinter instancing problem ("pyimage# doesn't exist") for which no solution or workaround has yet been found. Requirements: This script requires Python 2.0+. It should be compatible with all later Python versions, and should run OK on all platforms for which there is a Tkinter version (part of the standard Python installation). Three Bippy modules are required: common.py, raster.py, and pds.py. PDS file conversion: This script comes with the ability to save a GIF and/or RAW of each PDS file viewed. This feature can be turned on below with saveGIF = 1 or saveRAW = 1. RAW data is saved as-is from the PDS file and likely will need equalizing or other adjustment in the destination software, while the GIF file is an equalized 8-bit version of the original. Note that, unless you have gammaPt = 1.0 below, the saved GIF will probably look different in other applications from how this script shows the image. Stereo pairs: If this script encounters a file name that ends in 'r' or 'R', it will check to see if there is a matching 'l' or 'L' file and, if so, will try to display the two together as a stereo pair. This can be turned off by setting doStereo = 0 below. Note that, if doStereo is enabled, the script will always display the left image by itself, and will always show the right image with the left. You can find stereo files here: ftp://pdsimage2.wr.usgs.gov/cdroms/mars_pathfinder/mpim_0001/mars/seq0185/c1247xxx/ Possible changes: Probably will need some safety code for odd situations, like for gracefully exiting situations where apparent stereo pairs are actually mismatched. Before saving to RAW, have option to redistribute data within the available tonal range (the current unmanipulated results often need treatment, such as with Photoshop Image/Adjust/Auto Levels or /Equalize). Coordinate grayscale distribution between image pairs (this may need to wait for a viewing application with more sophistication). Please report script problems to: SUBJECT: Python but do _NOT_ send file attachments without first checking. Bippy = "Bill's Inter-Planetary Python" History: 2004-10-22 - small changes made in documentation above & below 2004-04-06 - final version """ #--- user-controlled variables --- """ debug =1 to print header & debug info, =0 to suppress doStereo =1 to combine 2 l/r images into stereo, =0 to suppress gammaPt =1.0 or decimal number, affects only screen view brightness, not file killTemp =1 to erase temporary files when done, =0 to leave in temp folder saveGIF =1 to output GIF file of same name in same folder, =0 to suppress saveRAW =1 to output RAW file at true bit depth, =0 to suppress notes: 1) can create lots of big files & 2) data is left at original values rather than redistributed to full available tonal range """ debug = 0 doStereo = 1 gammaPt = 1.5 killTemp = 1 saveGIF = 0 saveRAW = 0 """ Default: exclude = [] Can be = ['n0449.img','n0450.img'] Note: There's no need to exclude files that aren't in the acceptedFiles list. """ exclude = [] """ Default: acceptedFiles = ['.img','.pds'] """ acceptedFiles = ['.img','.pds'] #--- modules & constants --- import os, sys, tempfile import Tkinter as tk from string import strip thisDir = os.path.split(sys.argv[0])[0] if not thisDir in sys.path: sys.path.append(thisDir) workDir = os.path.split(thisDir)[0] import pds, raster from common import fixPath #--- Tkinter stuff --- class mainWindowClass: def __init__(self,master,tmpdir,w='640',h='480'): self.frame = tk.Toplevel(master) self.frame.title('Tkinter test-pds-tk.py') maxW = self.frame.winfo_screenwidth() - 4 maxH = self.frame.winfo_screenheight() - 52 self.flagXbar = 0 self.flagYbar = 0 if int(w) > maxW: w = str(maxW) self.flagXbar = 1 else: w = str(w) if int(h) > maxH: h = str(maxH) self.flagYbar = 1 else: h = str(h) self.frame.geometry(w+'x'+h+'+0+0') self.frame.resizable(0,0) self.canvas = tk.Canvas(self.frame,bg='white',bd=3,relief='sunken') self.canvas.pack(side='top',anchor='nw',fill='both',expand=1) self.frame.protocol('WM_DELETE_WINDOW',self.quit) #close button self.tempDir = tmpdir self.tempFiles = [] #kill list def post(self,rasObj,title=''): if not title: title = rasObj.fileName() if saveRAW: #save original image as RAW pn = rasObj.filePath() if pn: raster.rawWrite(rasObj,pn) if rasObj.typecode() != 'B': #not 8-bit needed for display rasObj,msg = raster.make8bit(rasObj) #new 8-bit, equalized object if not rasObj: print msg return pn = tempfile.mktemp(suffix='.pgm') self.tempFiles.append(pn) retval,msg = raster.pgmWrite(rasObj,pn) if retval: rasObj.history.append(msg) else: print 'pgmWrite failed:',msg return self.phid = tk.PhotoImage(file=pn) #MUST be self.phid, don't discard! self.phid.config(gamma=gammaPt) cvID = self.canvas.create_image(0,0,image=self.phid,anchor='nw', tag='tag') self.frame.title(title) self.frame.update_idletasks() if saveGIF: pn = rasObj.filePath() if pn: pn = pn[:-3] + 'gif' if not os.path.exists(pn): self.phid.write(pn) if self.flagXbar or self.flagYbar: cv = self.canvas if self.flagYbar: sc = self.yScroll = tk.Scrollbar(cv,command=cv.yview) sc.pack(side='right',fill='y') cv.config(yscrollcommand=sc.set) if self.flagXbar: sc = self.picFxScroll \ = tk.Scrollbar(cv,orient='horizontal',command=cv.xview) sc.pack(side='bottom',fill='x') cv.config(xscrollcommand=sc.set) cv.config(scrollregion=(0,0,rasObj.width()+10,rasObj.height()+10)) def quit(self): if killTemp: #delete temporary files for pn in self.tempFiles: try: os.remove(pn) except: pass self.frame.destroy() #end class mainWindowClass #--- main function --- def viewFile(): print '\nUsing Tkinter to test PDS processing with files in', \ workDir,'folder' #--- establish temporary file location tempDir = fixPath(thisDir,'temp') if not os.path.exists(tempDir): try: os.mkdir(tempDir) #can't find temp dir so make one except: tempDir = workDir #can't do temp dir so use work dir tempfile.tempdir = tempDir #--- pick a file to view oldList = [] seenFile = fixPath(tempDir,'seen.txt') #read in list of previously viewed if os.path.exists(seenFile): f = open(seenFile,'r') while 1: fn = f.readline() if not fn: break fn = strip(fn) if fn: oldList.append(fn) f.close() newList = [] dir = os.listdir(workDir) #create list of files in folder for fn in dir: if fn[-4:] in acceptedFiles: if not fn in exclude: newList.append(fn) if len(newList) == 0: print 'No file(s) found\nDONE with testing.' print ' oldList =',oldList print ' newList =',newList return newList.sort() seenList = [] for fn in oldList: #tune list of previously viewed if fn in newList and not fn in exclude: #eliminate unwanted files seenList.append(fn) # & files not still in folder fnView = '' for fn in newList: #find a file not yet viewed if not fn in seenList: fnView = fn break if not fnView: #have viewed all available files seenList = [] # so start over at the top fnView = newList[0] #--- load the file to view gotPair = 0 if fnView[-5] in ['r','R'] and doStereo: #check for stereo pair #***DEVnote: will fail for file name suffixes if not 3-char. long fnCheck = fnView[:-5] + 'l' + fnView[-4:] #lower-case 'l' if fnCheck in seenList: gotPair = 1 else: fnCheck = fnView[:-5] + 'L' + fnView[-4:] #upper-case 'L' if fnCheck in seenList: gotPair = 1 if gotPair: rasObjL,msg = pds.parsePDS(workDir,fnCheck,verbose=debug) rasObjR,msg = pds.parsePDS(workDir,fnView,verbose=debug) rasObj,msg = raster.stitch(rasObjL,rasObjR) else: rasObj,msg = pds.parsePDS(workDir,fnView,verbose=debug) if rasObj: if msg: print 'pds.parsePDS message:',msg if debug: print ' raster object history:' for s in rasObj.history: print ' >',s print ' --- begin PDS header ---' print rasObj.header print ' --- end of PDS header ---' root = tk.Tk() root.withdraw() mainWin = mainWindowClass(root,tempDir,rasObj.width(),rasObj.height()) mainWin.post(rasObj) root.wait_window(mainWin.frame) if debug: print ' --- begin history ---' for s in rasObj.history: print s print ' --- end history ---' seenList.append(fnView) f = open(seenFile,'w') for fn in seenList: f.write(fn+'\n') f.flush() f.close() else: print 'no raster object was returned' print ' message:',msg print 'DONE with testing.' #end def viewfile viewFile() ### end script ###