#---------------------------------------------------------------------- # Basic command processor # # Copyright (C) October 11, 2017 -- Dr. William T. Verts # Enhanced October 13, 2017 to be a graphics image processor # # This program ilustrates a number of new Python structures, including # quoted strings that span lines, the string function to make all # characters lower case, the raw_input function, the pass statement # to act as a placeholder for future code, and the use of bool # (Boolean) variables to control a loop. # # The new Python statements this time are the try-except block for # error handling, and the ability to pass functions as parameters to # other functions. # # In terms of command processor design, the main issues here are: # A: Do I put action code inside the individual if-statements of the # command processor? # B: Do I put action code inside individual functions called from # the command processor? # C: Can I factor common code out of the functions to generalize? #---------------------------------------------------------------------- # Approach B: Individual functions that do unique tasks def Brighten (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) setRed(PX, getRed(PX) + 30) setGreen(PX, getGreen(PX) + 30) setBlue(PX, getBlue(PX) + 30) repaint(Canvas) return def Darken (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) setRed(PX, getRed(PX) - 30) setGreen(PX, getGreen(PX) - 30) setBlue(PX, getBlue(PX) - 30) repaint(Canvas) return def MoreRed(Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) setRed(PX, getRed(PX) + 30) repaint(Canvas) return #---------------------------------------------------------------------- # Approach C: Tiny pixel-handler functions passed # in as parameters to the Process function. def Brighten_Pixel (PX): setRed(PX, getRed(PX) + 30) setGreen(PX, getGreen(PX) + 30) setBlue(PX, getBlue(PX) + 30) return def Darken_Pixel (PX): setRed(PX, getRed(PX) - 30) setGreen(PX, getGreen(PX) - 30) setBlue(PX, getBlue(PX) - 30) return #-------------------------------------------------- # Process is responsible for scanning all pixels # in an image and applying whatever is passed in # as MyFunction to each pixel, and repainting the # canvas after each line is completed. If Process # is passed Brighten_Pixel, then calling MyFunction # is the same as calling Brighten_Pixel. If Process # is passed Darken_Pixel, then calling MyFunction # is the same as calling Darken_Pixel. def Process(Canvas, MyFunction): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) MyFunction(PX) repaint(Canvas) return #---------------------------------------------------------------------- def Main(): #-------------------------------------------------- # Message uses the "triple-double-quote" of Python to build a # string that spans lines and contains line-breaks. Between the # opening """ and the closing """ all characters are valid, so # indentation is not used. Message = """ Stop Open Brighten Darken MoreRed MoreGreen MoreBlue Enter a command --- """ Canvas = makeEmptyPicture(100,100) show(Canvas) Stop = False while (not Stop): Command = requestString(Message) # Use requestString(Message) for JES dialog, raw_input for pure Python box Command = Command.lower() # Convert string to lower case (users may enter upper case by accident) if (Command == "stop"): Stop = True elif (Command == "open"): Filename = pickAFile() try: # If the user enters the name Canvas = makePicture(Filename) # of a file that isn't a graphic, repaint(Canvas) # the repaint will fail, and throw except: # an exception, picked up by the Canvas = makeEmptyPicture(100,100) # except block. If the try block showInformation(Filename + " is not a graphic") # succeeds, the except block won't run. #-------------------------------------------------- # Approach C: each command calls a handler function (Process) # responsible for overall image scanning, but passes # in as a parameter the appropriate function to use to # process each pixel (Brighten_Pixel, Darken_Pixel). elif (Command == "brighten"): Process(Canvas, Brighten_Pixel) elif (Command == "darken"): Process(Canvas, Darken_Pixel) #-------------------------------------------------- # Approach B: each command calls a unique function # dedicated to solving that one task. elif (Command == "morered"): MoreRed(Canvas) #-------------------------------------------------- # Approach A: each command in the command processor # does "its thing" right at the point that the new # command is known. Effective, but makes the command # processor extremely lengthy and hard to debug (how # easy is it to line up the proper indentation if this # part of the code is 800 lines long? elif (Command == "moregreen"): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) setGreen(PX, getGreen(PX) + 30) repaint(Canvas) elif (Command == "moreblue"): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) setBlue(PX, getBlue(PX) + 30) repaint(Canvas) else: print Command + " is an illegal command" # Use showMessage(...) for JES, print for pure Python dialog box repaint(Canvas) return