diff --git a/logos/wyo_logo.png b/logos/wyo_logo.png new file mode 100644 index 00000000..14c15374 Binary files /dev/null and b/logos/wyo_logo.png differ diff --git a/scripts/configuration.py b/scripts/configuration.py index e72df189..1a308a4c 100755 --- a/scripts/configuration.py +++ b/scripts/configuration.py @@ -6,13 +6,15 @@ class Configuration(): """Configuration class acts as configuration keys/values holder""" # default values user_name = None - logo_file = None + logo_file = "../logos/wyo_logo.png" + enable_logo = True countdown1 = 5 # seconds of preview before first snap countdown2 = 3 # seconds of preview between snaps (Four pictures mode) photoCaption = "" # Caption in the photo album ARCHIVE = True # Do we archive photos locally archive_dir = os.path.join("..","Photos") # Where do we archive photos archive_to_all_usb_drives = True + usb_mount_point_root = "/media/pi/" albumID = None # use install_credentials.py to create 'album.id' album_name = "Drop Box" emailSubject = "Here's your photo!" # subject line of the email sent from the photobooth @@ -20,6 +22,8 @@ class Configuration(): full_screen = True #Start application in full screen enable_email = True #Enable the 'send email" feature enable_upload = True #Enable the upload feature + enable_nine_button = True #Enable the nine photo collage feature + enable_anim_button = True #Enable the animation feature enable_print = False #Enable the printer feature enable_effects = True selected_printer = None #No printer select @@ -47,35 +51,39 @@ def __read_config_file(self): file_content = content_file.read() config = json.loads(file_content) except Exception as error: - print "Error while parsing %s config file : %s"%(self.config_file,error) + print("Error while parsing %s config file : %s"%(self.config_file,error)) self.is_valid = False return False - if "gmail_user" in config.keys(): self.user_name = config['gmail_user'] + if "gmail_user" in list(config.keys()): self.user_name = config['gmail_user'] else: #mandatory configuration!! self.is_valid = False # all other configuration keys are optional - if "countdown_before_snap" in config.keys(): self.countdown1 = config["countdown_before_snap"] - if "countdown_inter_snap" in config.keys(): self.countdown2 = config["countdown_inter_snap"] - if "snap_caption" in config.keys(): self.photoCaption = config["snap_caption"] - if "local_archive" in config.keys(): self.ARCHIVE = config["local_archive"] - if "archive_to_all_usb_drives" in config.keys(): self.archive_to_all_usb_drives = config["archive_to_all_usb_drives"] - if "local_archive_dir" in config.keys(): self.archive_dir = config["local_archive_dir"] - if "google_photo_album_id" in config.keys(): self.albumID = config["google_photo_album_id"] - if "google_photo_album_name" in config.keys(): self.album_name = config["google_photo_album_name"] - if "email_subject" in config.keys(): self.emailSubject = config["email_subject"] - if "email_body" in config.keys(): self.emailMsg = config["email_body"] - if "logo_file" in config.keys(): self.logo_file = config["logo_file"] - if "full_screen" in config.keys(): self.full_screen = config["full_screen"] - if "enable_email" in config.keys(): self.enable_email = config["enable_email"] - if "enable_upload" in config.keys(): self.enable_upload = config["enable_upload"] - if "enable_print" in config.keys(): self.enable_print = config["enable_print"] - if "enable_effects" in config.keys(): self.enable_effects = config["enable_effects"] - if "selected_printer" in config.keys(): self.selected_printer = config["selected_printer"] - if "enable_hardware_buttons" in config.keys(): self.enable_hardware_buttons = config["enable_hardware_buttons"] - if "enable_email_logging" in config.keys(): self.enable_email_logging = config["enable_email_logging"] + if "countdown_before_snap" in list(config.keys()): self.countdown1 = config["countdown_before_snap"] + if "countdown_inter_snap" in list(config.keys()): self.countdown2 = config["countdown_inter_snap"] + if "snap_caption" in list(config.keys()): self.photoCaption = config["snap_caption"] + if "local_archive" in list(config.keys()): self.ARCHIVE = config["local_archive"] + if "archive_to_all_usb_drives" in list(config.keys()): self.archive_to_all_usb_drives = config["archive_to_all_usb_drives"] + if "usb_mount_point_root" in list(config.keys()): self.usb_mount_point_root = config["usb_mount_point_root"] + if "local_archive_dir" in list(config.keys()): self.archive_dir = config["local_archive_dir"] + if "google_photo_album_id" in list(config.keys()): self.albumID = config["google_photo_album_id"] + if "google_photo_album_name" in list(config.keys()): self.album_name = config["google_photo_album_name"] + if "email_subject" in list(config.keys()): self.emailSubject = config["email_subject"] + if "email_body" in list(config.keys()): self.emailMsg = config["email_body"] + if "logo_file" in list(config.keys()): self.logo_file = config["logo_file"] + if "enable_logo" in list(config.keys()): self.enable_logo = config["enable_logo"] + if "full_screen" in list(config.keys()): self.full_screen = config["full_screen"] + if "enable_email" in list(config.keys()): self.enable_email = config["enable_email"] + if "enable_upload" in list(config.keys()): self.enable_upload = config["enable_upload"] + if "enable_nine_button" in list(config.keys()): self.enable_nine_button = config["enable_nine_button"] + if "enable_anim_button" in list(config.keys()): self.enable_anim_button = config["enable_anim_button"] + if "enable_print" in list(config.keys()): self.enable_print = config["enable_print"] + if "enable_effects" in list(config.keys()): self.enable_effects = config["enable_effects"] + if "selected_printer" in list(config.keys()): self.selected_printer = config["selected_printer"] + if "enable_hardware_buttons" in list(config.keys()): self.enable_hardware_buttons = config["enable_hardware_buttons"] + if "enable_email_logging" in list(config.keys()): self.enable_email_logging = config["enable_email_logging"] return self.is_valid @@ -90,15 +98,19 @@ def write(self): "snap_caption": self.photoCaption, "local_archive" : self.ARCHIVE, "archive_to_all_usb_drives" : self.archive_to_all_usb_drives, + "usb_mount_point_root" : self.usb_mount_point_root, "local_archive_dir" : self.archive_dir, "google_photo_album_id" : self.albumID, "google_photo_album_name" : self.album_name, "email_subject": self.emailSubject, "email_body":self.emailMsg, "logo_file": self.logo_file, + "enable_logo": self.enable_logo, "full_screen": self.full_screen, "enable_email": self.enable_email, "enable_upload": self.enable_upload, + "enable_nine_button": self.enable_nine_button, + "enable_anim_button": self.enable_anim_button, "enable_print": self.enable_print, "enable_effects": self.enable_effects, "selected_printer": self.selected_printer, diff --git a/scripts/constants.py b/scripts/constants.py index 597f2dc7..63948c9b 100755 --- a/scripts/constants.py +++ b/scripts/constants.py @@ -42,11 +42,11 @@ }, "Four": { 'snap_size' : (820,616), #(width, height) of each shots of the 2x2 collage - 'foreground_image' : "../logos/collage_four_square_logo.png" # Overlay image on top of the collage + 'foreground_image' : "../logos/collage_four_square.png" # Overlay image on top of the collage }, "Nine": { 'snap_size' : (546,410), #(width, height) of each shots of the 2x2 collage - 'foreground_image' : "../logos/collage_nine_square_logo.png" # Overlay image on top of the collage + 'foreground_image' : "../logos/collage_nine_square.png" # Overlay image on top of the collage }, "Animation": { 'snap_size' : (500, 500), #(width, height) => Caution, gif animation can be huge, keep this small @@ -60,18 +60,22 @@ SOFTWARE_BUTTONS = { "Four": { "icon" : os.path.join("ressources","ic_four.png"), + "enabled": True, "order":1 }, "Nine": { "icon" : os.path.join("ressources","ic_nine.png"), + "enabled": True, "order":2 }, "None": { "icon" : os.path.join("ressources","ic_portrait.png"), + "enabled": True, "order":0 }, "Animation": { "icon" : os.path.join("ressources","ic_anim.png"), + "enabled": True, "order":3 } } diff --git a/scripts/cv2_camera.py b/scripts/cv2_camera.py index 8a6de6eb..7efb7d75 100755 --- a/scripts/cv2_camera.py +++ b/scripts/cv2_camera.py @@ -52,5 +52,5 @@ def test(): cv2.destroyAllWindows() if __name__ == '__main__': - print 'type "q" to quit' + print('type "q" to quit') test() diff --git a/scripts/hardware_buttons.py b/scripts/hardware_buttons.py index a4478c6d..410186c1 100755 --- a/scripts/hardware_buttons.py +++ b/scripts/hardware_buttons.py @@ -105,15 +105,15 @@ def state(self): buttons = Buttons() last = 0 if buttons.has_buttons(): - print "Press hardware buttons to see change, ctrl+C to exit" + print("Press hardware buttons to see change, ctrl+C to exit") else: - print "No button configured (no access to GPIO or empty button list)" - print "Number of buttons is %d" % buttons.buttons_number() + print("No button configured (no access to GPIO or empty button list)") + print("Number of buttons is %d" % buttons.buttons_number()) sys.exit() while True: state = buttons.state() if last != state: - print "new state: %d"%state + print("new state: %d"%state) last = state time.sleep(0.1) diff --git a/scripts/mykb.py b/scripts/mykb.py index 00c4dd29..65fa89e4 100755 --- a/scripts/mykb.py +++ b/scripts/mykb.py @@ -49,10 +49,11 @@ """ +import re import logging log=logging.getLogger(__name__) -from Tkinter import * +from tkinter import * class Key: """Implements common behavior for a Keyboard Key""" @@ -131,7 +132,7 @@ def set_mode(self,mode): """ self.mode = mode self.current_value = "" - for state in self.key_states.keys(): + for state in list(self.key_states.keys()): if state == mode: self.canvas.itemconfigure(state,state="normal") self.current_value = self.key_states[state] @@ -539,7 +540,7 @@ def apply_stylesheet(self,stylesheet): self.bound_entry.configure(font=styledef["font"]) continue #print "Applying stylesheet for %s"%tag - for style in styledef.keys(): + for style in list(styledef.keys()): try: if style == 'tag' : continue #apply all styles to tag @@ -562,7 +563,7 @@ def apply_stylesheet(self,stylesheet): except: pass self.canvas.update() - except Exception, e: + except Exception as e: log.exception("Error while applying stylesheet") __email_validator = re.compile(r'^[^@]+@[^@]+\.[^@]+$') @@ -573,11 +574,11 @@ def email_validator(addr): r = Tk() myres = StringVar() def onEnter(): - print 'Enter Pressed' - print "result %s"%myres.get() + print('Enter Pressed') + print("result %s"%myres.get()) def onCancel(): - print 'Cancel Pressed' - print "result %s"%myres.get() + print('Cancel Pressed') + print("result %s"%myres.get()) keyboard = TouchKeyboard(r,myres, onEnter = onEnter, onCancel=onCancel, validator=email_validator) diff --git a/scripts/oauth2services.py b/scripts/oauth2services.py index d12a6f02..a06e724c 100755 --- a/scripts/oauth2services.py +++ b/scripts/oauth2services.py @@ -170,7 +170,7 @@ def get_user_albums(self, as_title_id = True, exclude_non_app_created_data = Tru for album in albums: entry = {} #skip albums with no title - if not ("title" in album.keys()): + if not ("title" in list(album.keys())): continue entry['title'] = album.get("title") entry['id'] = album.get("id") @@ -365,7 +365,7 @@ def test(): """ test email and uploading """ logging.basicConfig() - username = raw_input("Please enter your email address: ") + username = input("Please enter your email address: ") # creating test image from PIL import Image @@ -380,20 +380,20 @@ def test(): gservice = OAuthServices("client_id.json","storage.json",username,log_level=logging.DEBUG) - print "\nTesting email sending..." - print gservice.send_message(username,"oauth2 message sending works!","Here's the Message body",attachment_file="test_image.png") - print "\nTesting album list retrieval..." + print("\nTesting email sending...") + print(gservice.send_message(username,"oauth2 message sending works!","Here's the Message body",attachment_file="test_image.png")) + print("\nTesting album list retrieval...") albums = gservice.get_user_albums() for i, album in enumerate(albums): - print "\t title: %s, id: %s"%(album['title'],album['id']) + print("\t title: %s, id: %s"%(album['title'],album['id'])) if i >= 10: - print "skipping the remaining albums..." + print("skipping the remaining albums...") break - print "\nTesting album creation and image upload" + print("\nTesting album creation and image upload") album_id = gservice.create_album(album_name="Test", add_placeholder_picture = True) - print "New album id:",album_id + print("New album id:",album_id) print("Uploading to a bogus album") - print(gservice.upload_picture("testfile.png",album_id = "BOGUS STRING" , caption="In bogus album", generate_placeholder_picture = True)) + print((gservice.upload_picture("testfile.png",album_id = "BOGUS STRING" , caption="In bogus album", generate_placeholder_picture = True))) if __name__ == '__main__': diff --git a/scripts/screenshot.py b/scripts/screenshot.py index 8a582fff..39e5a81d 100755 --- a/scripts/screenshot.py +++ b/scripts/screenshot.py @@ -31,7 +31,7 @@ def snap(delay=0): fn = "%4d-%02d-%02d_%02d%02d%02d.jpg" % (Y, M, D, h, m, s) fn = os.path.join(pictures, fn) ImageGrab.grab().save(fn, "JPEG") - print 'saved', fn + print('saved', fn) if __name__ == '__main__': snap(delay=5) diff --git a/scripts/setup.py b/scripts/setup.py index d10dd442..63625213 100755 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -17,16 +17,16 @@ import cups printer_selection_enable = True except ImportError: - print "Cups not installed. removing option" + print("Cups not installed. removing option") printer_selection_enable = False VALID_ICON_FILE = os.path.join("ressources","ic_valid.png") INVALID_ICON_FILE = os.path.join("ressources","ic_invalid.png") from PIL import Image as _Image from PIL import ImageTk as _ImageTk -from Tkinter import * -import tkFileDialog -import tkMessageBox +from tkinter import * +import tkinter.filedialog +import tkinter.messagebox import oauth2services #URL of the Google console developer assistant to create App_id file @@ -100,7 +100,7 @@ def on_want_print_change(*args): self.use_print_list.insert(END, printer) self.__draw_page() except: - tkMessageBox.showerror("Missing Driver","""You need CUPS installed and a printer setup. Please look in the Readme file for a link on how to setup CUPS on your system. The printer option will be disabled for this setup.""") + tkinter.messagebox.showerror("Missing Driver","""You need CUPS installed and a printer setup. Please look in the Readme file for a link on how to setup CUPS on your system. The printer option will be disabled for this setup.""") self.__erase_page() self.widgets.pop(0) self.widgets.insert(0,[self.want_email_cb, self.want_upload_cb,self.want_effects_cb, self.use_soft_keyboard_cb]) @@ -130,7 +130,7 @@ def on_use_printer(evt): self.want_printer_val = int(printer_selected.curselection()[0]) self.config.selected_printer = int(self.want_printer_val) #value = self.want_printer_val.get(index) - print 'You selected item %d: ' % (self.want_printer_val) + print('You selected item %d: ' % (self.want_printer_val)) #checkbutton to choose to use soft keyboard @@ -256,14 +256,14 @@ def on_albumID_change(*args): def select_album(): """Popup control to select albums""" - print "Album selection" + print("Album selection") connected=False try: connected = self.google_service.refresh() except: pass if not connected: - print "Error: impossible to connect to Google\n" + print("Error: impossible to connect to Google\n") return #Create an album selection control top = Toplevel(self,bg='white') @@ -322,7 +322,7 @@ def item_selected(*args): #print cursel #print displayed_list_ids #print displayed_list_names - print "selected album '%s' with id '%s'"%(displayed_list_names[cursel],displayed_list_ids[cursel]) + print("selected album '%s' with id '%s'"%(displayed_list_names[cursel],displayed_list_ids[cursel])) if displayed_list_names[cursel] == "": try: #No album found, create one @@ -382,9 +382,9 @@ def on_archive_dir_change(*args): self.archive_dir_entry = Entry(self.main_frame, textvariable=self.archive_dir_var, width = 40, font='Helvetica') self.__install_soft_keyboard(self.archive_dir_entry,self.archive_dir_var) def change_dir(): - directory = tkFileDialog.askdirectory(initialdir=self.archive_dir_var.get(), title="Choose directory for snapshots archive") + directory = tkinter.filedialog.askdirectory(initialdir=self.archive_dir_var.get(), title="Choose directory for snapshots archive") self.archive_dir_var.set(directory) - print "changed dir to %s"%directory + print("changed dir to %s"%directory) self.choose_archive_dir_button = Button(self.main_frame, text="Choose directory", fg='white',bg=self.BUTTONS_BG, font='Helvetica', command=change_dir) @@ -427,11 +427,11 @@ def __mail_body_update_content(self): return self.email_body_var.get() def __remove_app_id(self): - print "removing %s"%constants.APP_ID_FILE + print("removing %s"%constants.APP_ID_FILE) self.__ask_for_removal(constants.APP_ID_FILE,"Are you sure you want to remove the App ID file?\nYou'll need to download it again from your developer's console.") def __remove_cred_store(self): - print "removing %s"%constants.CREDENTIALS_STORE_FILE + print("removing %s"%constants.CREDENTIALS_STORE_FILE) self.__ask_for_removal(constants.CREDENTIALS_STORE_FILE,"Are you sure you want to remove the credentials storage file?\nYou'll need to authorize your application again.") def __install_soft_keyboard(self,entry,stringvar): @@ -447,7 +447,7 @@ def kill_keyboard(): self.soft_keyboard.destroy() self.soft_keyboard = None def onEnter(*args): - print "updating value" + print("updating value") if entry.winfo_class() == 'Text': #copy the content of stringvar that just got modified into the text text_content = stringvar.get() @@ -462,7 +462,7 @@ def onEnter(*args): entry.bind('',launch_keyboard) def __get_app_id(self): - print "Getting App ID" + print("Getting App ID") message=""" ________________________________________________________________ Photo upload or email sending requires that you create a @@ -517,7 +517,7 @@ def launch_browser(): self.__check_credentials_files() def __connect_app(self): - print "Connecting App" + print("Connecting App") #Create a graphical handler for the authorization def auth_handler(URI): @@ -571,31 +571,31 @@ def authenticate(): self.wait_window(top) #update displayed - print "returning code %s"%auth_code.get() + print("returning code %s"%auth_code.get()) return auth_code.get() - print "Trying the connexion" + print("Trying the connexion") #try to connect try: self.google_service = oauth2services.OAuthServices(constants.APP_ID_FILE,constants.CREDENTIALS_STORE_FILE,self.user_mail_var.get() ) - print self.google_service.refresh() + print(self.google_service.refresh()) except Exception as error: self.google_service = None - print error + print(error) import traceback traceback.print_exc() self.__check_credentials_files() def __ask_for_removal(self,file,message): - result = tkMessageBox.askquestion("Delete File", message, icon='warning') + result = tkinter.messagebox.askquestion("Delete File", message, icon='warning') if result == 'yes': try: os.remove(file) - print "%s deleted"%file + print("%s deleted"%file) except: pass else: - print "Canceled" + print("Canceled") #repaint the control self.__check_credentials_files() @@ -737,7 +737,7 @@ def __draw_page(self): self.packed_widgets.append(w) def __save_and_exit(self): - print "bye!" + print("bye!") #finally create a personalized script to run the photobooth install_dir = os.path.split(os.path.abspath(__file__))[0] script_name = os.path.join(os.path.abspath(".."),"photobooth.sh") @@ -761,7 +761,7 @@ def __test_connection(self,test_email,test_upload): return username = self.user_mail_var.get() if self.google_service is None: - print "Unable to test service: no connection" + print("Unable to test service: no connection") return False # creating test image (a 32x32 image with random color) @@ -773,10 +773,10 @@ def __test_connection(self,test_email,test_upload): im = Image.new("RGB", (32, 32), (r,g,b)) im.save("test_image.png") if test_email: - print "\nSending a test message to %s"%username + print("\nSending a test message to %s"%username) self.google_service.send_message(username,self.config.emailSubject,self.config.emailMsg,attachment_file="test_image.png") if test_upload: - print "\nTesting picture upload in %s's album with id %s:"%(username,self.config.albumID) + print("\nTesting picture upload in %s's album with id %s:"%(username,self.config.albumID)) self.google_service.upload_picture("test_image.png", album_id = self.config.albumID) @@ -799,7 +799,7 @@ def graphical_assistant(): def console_assistant(): """Launches the text-based interface""" - print """ + print(""" ________________________________________________________________ Welcome to the installation assistant! @@ -807,7 +807,7 @@ def console_assistant(): credentials ________________________________________________________________ - """ + """) install_dir = os.path.split(os.path.abspath(__file__))[0] @@ -817,14 +817,14 @@ def console_assistant(): config.enable_email = ask_boolean("Do you want the 'send photo by email' feature?",config.enable_email) - print "" + print("") config.enable_upload = ask_boolean("Do you want the 'auto-upload photos' feature?",config.enable_upload) - print "" + print("") config.enable_effects = ask_boolean("Do you want the 'Photos effects' feature?",config.enable_effects) - print "" + print("") if printer_selection_enable == True: config.enable_print = ask_boolean("Do you want the 'Send photo to printer' feature?", config.enable_print) - print "" + print("") if config.enable_print == True: conn = cups.Connection() printers = conn.getPrinters() @@ -832,13 +832,13 @@ def console_assistant(): selectedindex = 0 for printer in printers: if config.selected_printer == str(index): - print '[*] ['+str(index)+'] '+printer + print('[*] ['+str(index)+'] '+printer) selectedindex = index else: - print '[ ] ['+str(index)+'] '+printer + print('[ ] ['+str(index)+'] '+printer) index = index + 1 - config.selected_printer = raw_input("Seleted printer: [%s] confirm or change =>" % config.selected_printer) - if config.selected_printer is "": config.selected_printer = selectedindex + config.selected_printer = input("Seleted printer: [%s] confirm or change =>" % config.selected_printer) + if config.selected_printer == "": config.selected_printer = selectedindex want_email = config.enable_email want_upload = config.enable_upload @@ -852,7 +852,7 @@ def console_assistant(): config.write() if need_credentials: # Check for user account - _username = raw_input("Google account: [%s] confirm or change => " % config.user_name) + _username = input("Google account: [%s] confirm or change => " % config.user_name) if _username != "": config.user_name = _username.strip() config.write() @@ -860,9 +860,9 @@ def console_assistant(): app_id = os.path.join(install_dir,constants.APP_ID_FILE) if os.path.exists(app_id): - print "\n** found %s application file, will use it (remove in case of problems)"%constants.APP_ID_FILE + print("\n** found %s application file, will use it (remove in case of problems)"%constants.APP_ID_FILE) else: - print """ + print(""" ________________________________________________________________ Photo upload or email sending requires that you create a @@ -889,79 +889,79 @@ def console_assistant(): The installation program will now exit. Run it again once this is done - """%(app_id) + """%(app_id)) sys.exit() # We do have the client_id ! cred_store = os.path.join(install_dir,constants.CREDENTIALS_STORE_FILE) if os.path.exists(cred_store): - print "\n** Found %s credential store"%constants.CREDENTIALS_STORE_FILE - remove_file = to_boolean(raw_input("If you have troubles connecting you may want to remove this file\nRemove ? [N/y] => "),False) + print("\n** Found %s credential store"%constants.CREDENTIALS_STORE_FILE) + remove_file = to_boolean(input("If you have troubles connecting you may want to remove this file\nRemove ? [N/y] => "),False) if remove_file: try: os.remove(cred_store) except: import traceback traceback.print_exc() - print "\n==> Problem removing %s file, please do it on your side and run this assistant again\n"%cred_store + print("\n==> Problem removing %s file, please do it on your side and run this assistant again\n"%cred_store) sys.exit() # prepare the validation callback in case of missing or invalid credential store import webbrowser def auth_callback(authorization_uri): - print "\n%s file is missing or invalid"%cred_store - print """ + print("\n%s file is missing or invalid"%cred_store) + print(""" _________________________________________________________________ You must authorize this application to access your data I will now open a web browser to complete the validation process Once this is done, you will get a validation key that you must paste below - _________________________________________________________________""" - raw_input("Press a key when ready...") + _________________________________________________________________""") + input("Press a key when ready...") webbrowser.open(authorization_uri) - mycode = raw_input('\n[validation code]: ').strip() + mycode = input('\n[validation code]: ').strip() return mycode import oauth2services try: - print "\n** Connecting..." + print("\n** Connecting...") service = oauth2services.OAuthServices(app_id,cred_store,config.user_name) connected = service.refresh() # will call 'auth_callback' if needed - print "... Done" + print("... Done") except Exception as error: - print error - print "\n==> Connection failed :(" + print(error) + print("\n==> Connection failed :(") sys.exit() if not connected: - print "\nThere was an error during the connection" - print "Please check your network connection and/or reauthorize this application" - print "Exiting..." + print("\nThere was an error during the connection") + print("Please check your network connection and/or reauthorize this application") + print("Exiting...") sys.exit() if config.albumID != None: - keep_album = to_boolean(raw_input("Photo Album is configured (%s), do you want to keep it? [Y/n] => "%config.album_name)) + keep_album = to_boolean(input("Photo Album is configured (%s), do you want to keep it? [Y/n] => "%config.album_name)) change_album_id = not keep_album else: - print "\nNo photo album selected, images will be uploaded to\nGoogle Photo Library (No Album)" - change_album_id = to_boolean(raw_input("\nDo you want to select another album for upload? [N/y] => ")) + print("\nNo photo album selected, images will be uploaded to\nGoogle Photo Library (No Album)") + change_album_id = to_boolean(input("\nDo you want to select another album for upload? [N/y] => ")) if change_album_id: try: - print "\nDownloading %s albums list..."% config.user_name + print("\nDownloading %s albums list..."% config.user_name) albums = service.get_user_albums() - print "... %d albums found"%(len(albums)) + print("... %d albums found"%(len(albums))) candidates = [] candidates_id = [] album_title = None album_id = None while True: - search_string = raw_input("Type a part of an existing album name (or return for all): ") + search_string = input("Type a part of an existing album name (or return for all): ") search_string = search_string.lower() candidates = ["",""] candidates_id = ["",""] @@ -973,21 +973,21 @@ def auth_callback(authorization_uri): candidates.append(title) candidates_id.append(id) if len(candidates) == 0: - print "Sorry: no match\n" + print("Sorry: no match\n") else: break - print "Here's the album that match:" + print("Here's the album that match:") for i, title in enumerate(candidates): - print "[%3d] %s"%(i,title) + print("[%3d] %s"%(i,title)) while True: - album_num = raw_input("Type album number => ") + album_num = input("Type album number => ") try: album_title = candidates[int(album_num)] album_id = candidates_id[int(album_num)] break except: - print "Bad album number!" + print("Bad album number!") if album_id == "": config.albumID = None elif album_id == "": @@ -997,21 +997,21 @@ def auth_callback(authorization_uri): config.albumID = album_id config.album_name = album_title config.write() - print "\nAlbum '%s' with id '%s' successfully selected!\n"%(album_title, album_id) + print("\nAlbum '%s' with id '%s' successfully selected!\n"%(album_title, album_id)) except: import traceback traceback.print_exc() - print "\n==> Error while fetching user albums, try to re-authenticate the application :(" + print("\n==> Error while fetching user albums, try to re-authenticate the application :(") # Optional tests for connection if config.enable_email: config.enable_email_logging = ask_boolean("Do you want to log outgoing email addresses?",config.enable_email_logging) config.write() - test_email = to_boolean(raw_input("Do you want to test email sending? [N/y] => "),False) + test_email = to_boolean(input("Do you want to test email sending? [N/y] => "),False) if config.enable_upload: - test_upload = to_boolean(raw_input("Do you want to test image upload? [N/y] => "),False) + test_upload = to_boolean(input("Do you want to test image upload? [N/y] => "),False) test_connection(service, config, test_email, test_upload) @@ -1027,7 +1027,7 @@ def auth_callback(authorization_uri): st = os.stat(script_name) os.chmod(script_name, st.st_mode | stat.S_IEXEC) - print """ + print(""" ________________________________________________________________ @@ -1036,7 +1036,7 @@ def auth_callback(authorization_uri): => %s You can tune configuration parameters in scripts/%s You can adapt your hardware configuration in scripts/constants.py - """% (script_name, constants.CONFIGURATION_FILE) + """% (script_name, constants.CONFIGURATION_FILE)) def to_boolean(answer, default=True): @@ -1057,7 +1057,7 @@ def ask_boolean(prompt, current_value): choice = "[Y/n]" else: choice = "[N/y]" - return to_boolean(raw_input("%s %s => "%(prompt,choice)),current_value) + return to_boolean(input("%s %s => "%(prompt,choice)),current_value) def test_connection(service,config,test_email,test_upload): """Tests email sending and/or image uploading""" @@ -1071,10 +1071,10 @@ def test_connection(service,config,test_email,test_upload): im = Image.new("RGB", (32, 32), "red") im.save("test_image.png") if test_email: - print "\nSending a test message to %s"%username + print("\nSending a test message to %s"%username) service.send_message(username,"oauth2 message sending works!","Here's the Message body",attachment_file="test_image.png") if test_upload: - print "\nTesting picture upload in %s's album"%username + print("\nTesting picture upload in %s's album"%username) service.upload_picture("test_image.png", album_id = config.albumID) @@ -1091,10 +1091,10 @@ def test_connection(service,config,test_email,test_upload): try: graphical_assistant() except Exception as error: - print error + print(error) #import traceback #traceback.print_exc() import time time.sleep(2) - print "\nError loading graphical assistant, default to console based\n" + print("\nError loading graphical assistant, default to console based\n") console_assistant() diff --git a/scripts/tkImageLabel.py b/scripts/tkImageLabel.py index c0c96629..2c995fab 100755 --- a/scripts/tkImageLabel.py +++ b/scripts/tkImageLabel.py @@ -5,7 +5,7 @@ https://stackoverflow.com/questions/43770847/play-an-animated-gif-in-python-with-tkinter Thanks! ''' -from Tkinter import * +from tkinter import * from PIL import ImageTk,Image from itertools import count import logging diff --git a/scripts/user_interface.py b/scripts/user_interface.py index b6d6b714..e6471ad0 100755 --- a/scripts/user_interface.py +++ b/scripts/user_interface.py @@ -13,8 +13,8 @@ filemode='w', level = logging.DEBUG) -from Tkinter import * -import tkMessageBox +from tkinter import * +import tkinter.messagebox from PIL import ImageTk,Image #from tkkb import Tkkb from mykb import TouchKeyboard, email_validator @@ -27,7 +27,7 @@ def argsort(seq): #http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3382369#3382369 #by unutbu - return sorted(range(len(seq)), key=seq.__getitem__) + return sorted(list(range(len(seq))), key=seq.__getitem__) def shuffle(l, swaps=50): import random @@ -58,7 +58,7 @@ def shuffle(l, swaps=50): import hardware_buttons as HWB except ImportError: log.error("Error importing hardware_buttons, using fakehardware instead") - print traceback.print_exc() + print(traceback.print_exc()) import fakehardware as HWB try: @@ -136,7 +136,13 @@ def __init__(self, config, window_size=None, poll_period=HARDWARE_POLL_PERIOD, l send_prints = config.enable_print image_effects = config.enable_effects selected_printer = config.selected_printer - + nine_button_enabled = config.enable_nine_button + anim_button_enabled = config.enable_anim_button + + ## Enable/Disable software buttons + SOFTWARE_BUTTONS['Nine']['enabled'] = nine_button_enabled + SOFTWARE_BUTTONS['Animation']['enabled'] = anim_button_enabled + self.root = Tk() ## Auto hide Mouse cursor @@ -167,7 +173,7 @@ def on_motion(event): ## Bind keyboard keys to actions def install_key_binding(action,function): - if action in ACTIONS_KEYS_MAPPING.keys(): + if action in list(ACTIONS_KEYS_MAPPING.keys()): for key in ACTIONS_KEYS_MAPPING[action]: self.log.debug("Installing keybinding '%s' for action '%s'"%(key,action)) self.root.bind(key,function) @@ -300,14 +306,15 @@ def safe_execute(args): total_width = 0 # first, open images and load them + compute the total width for i, effect in enumerate(SOFTWARE_BUTTONS): - self.log.debug(" adding %s" % effect) - effect_image = Image.open(SOFTWARE_BUTTONS[effect]['icon']) - w,h = effect_image.size - tkimage = ImageTk.PhotoImage(effect_image) - self.software_buttons_images[effect] = {} - self.software_buttons_images[effect]['image'] = tkimage - self.software_buttons_images[effect]['size'] = (w,h) - total_width = total_width + w + if SOFTWARE_BUTTONS[effect]['enabled']: + self.log.debug(" adding %s" % effect) + effect_image = Image.open(SOFTWARE_BUTTONS[effect]['icon']) + w,h = effect_image.size + tkimage = ImageTk.PhotoImage(effect_image) + self.software_buttons_images[effect] = {} + self.software_buttons_images[effect]['image'] = tkimage + self.software_buttons_images[effect]['size'] = (w,h) + total_width = total_width + w #we have the total size, compute padding padding = int((self.size[0] - total_width) / (len(SOFTWARE_BUTTONS) - 1)) # decurrying of callback parameter @@ -317,20 +324,21 @@ def snap_fun(): self.snap(effect) return snap_fun - effects = SOFTWARE_BUTTONS.keys() + effects = list(SOFTWARE_BUTTONS.keys()) orders = [SOFTWARE_BUTTONS[effect]["order"] for effect in effects] - for i in argsort(orders): + for i in argsort(orders): effect = effects[i] - effect_image = Image.open(SOFTWARE_BUTTONS[effect]['icon']) - w,h = self.software_buttons_images[effect]['size'] - Y = self.size[1] - h - tkimage = self.software_buttons_images[effect]['image'] - - btn = Button(self.root, image=tkimage, width = w, height= h, command=snap_factory(effect)) - self.software_buttons.append(btn) - btn.place(x=X_,y=Y) - btn.configure(background = 'black') - X_ = X_ + w + padding + if SOFTWARE_BUTTONS[effect]['enabled']: + effect_image = Image.open(SOFTWARE_BUTTONS[effect]['icon']) + w,h = self.software_buttons_images[effect]['size'] + Y = self.size[1] - h + tkimage = self.software_buttons_images[effect]['image'] + + btn = Button(self.root, image=tkimage, width = w, height= h, command=snap_factory(effect)) + self.software_buttons.append(btn) + btn.place(x=X_,y=Y) + btn.configure(background = 'black') + X_ = X_ + w + padding #Camera self.camera = mycamera.PiCamera() @@ -419,7 +427,22 @@ def run_periodically(self): elif btn_state == 3: self.snap("Animation") self.poll_after_id = self.root.after(self.poll_period, self.run_periodically) - + + def insert_logo(self, config, snapshot): + if config.enable_logo and config.logo is not None : + try: + size = snapshot.size + ### resize logo to the wanted size### TJS: I like to make logos the correct size to start with. + # config.logo.thumbnail((EFFECTS_PARAMETERS['None']['logo_size'],EFFECTS_PARAMETERS['None']['logo_size'])) + logo_size = config.logo.size + #put logo on bottom right with padding + yoff = size[1] - logo_size[1] - EFFECTS_PARAMETERS['None']['logo_padding'] + xoff = size[0] - logo_size[0] - EFFECTS_PARAMETERS['None']['logo_padding'] + self.log.debug("snap: adding logo '%s @ (%d, %d)'" % (config.logo_file, xoff, yoff)) + snapshot.paste(config.logo,(xoff, yoff), config.logo) + except Exception as e: + self.log.warning("Could not add logo to image : %r"%e) + def snap(self,mode="None"): """Snap a shot in given mode @@ -441,7 +464,7 @@ def snap(self,mode="None"): picture_saved = False picture_uploaded = False - if mode not in EFFECTS_PARAMETERS.keys(): + if mode not in list(EFFECTS_PARAMETERS.keys()): self.log.error("Wrong effectmode %s defaults to 'None'" % mode) mode = "None" @@ -476,19 +499,8 @@ def snap(self,mode="None"): snapshot = Image.open('snapshot.jpg') picture_taken = True - if config.logo is not None : - try: - size = snapshot.size - ### resize logo to the wanted size### TJS: I like to make logos the correct size to start with. - # config.logo.thumbnail((EFFECTS_PARAMETERS['None']['logo_size'],EFFECTS_PARAMETERS['None']['logo_size'])) - logo_size = config.logo.size - #put logo on bottom right with padding - yoff = size[1] - logo_size[1] - EFFECTS_PARAMETERS['None']['logo_padding'] - xoff = size[0] - logo_size[0] - EFFECTS_PARAMETERS['None']['logo_padding'] - self.log.debug("snap: adding logo '%s @ (%d, %d)'" % (config.logo_file, xoff, yoff)) - snapshot.paste(config.logo,(xoff, yoff), config.logo) - except Exception as e: - self.log.warning("Could not add logo to image : %r"%e) + self.insert_logo(config, snapshot) + self.log.debug("snap: saving snapshot") snap_filename = 'snapshot.jpg' snapshot.save(snap_filename) @@ -532,10 +544,10 @@ def snap(self,mode="None"): #print front snapshot=Image.alpha_composite(snapshot,front) - except Exception, e: + except Exception as e: self.log.error("snap: unable to paste collage cover: %s"%repr(e)) - + self.insert_logo(config, snapshot) self.status("") snapshot = snapshot.convert('RGB') self.log.debug("snap: Saving collage") @@ -553,7 +565,7 @@ def snap(self,mode="None"): h_ = h * 3 # take 9 photos and merge into one image. self.__show_countdown(config.countdown1,annotate_size = 80) - effects_keys = IMAGE_EFFECTS.keys() + effects_keys = list(IMAGE_EFFECTS.keys()) shuffle(effects_keys[1:]) effects_keys.insert(4, 'none') for i in range(9): @@ -585,8 +597,10 @@ def snap(self,mode="None"): #print front snapshot=Image.alpha_composite(snapshot,front) - except Exception, e: + except Exception as e: self.log.error("snap: unable to paste collage cover: %s"%repr(e)) + + self.insert_logo(config, snapshot) self.status("") snapshot = snapshot.convert('RGB') self.log.debug("snap: Saving collage") @@ -672,10 +686,9 @@ def snap(self,mode="None"): # Try to write the picture we've just taken to ALL plugged-in usb keys if config.archive_to_all_usb_drives: self.log.info("Archiving to USB keys") - try: - usb_mount_point_root = "/media/pi/" + try: import os - root, dirs, files = next(os.walk(usb_mount_point_root)) + root, dirs, files = next(os.walk(config.usb_mount_point_root)) for directory in dirs: mountpoint = os.path.join(root,directory) if mountpoint.find("SETTINGS") != -1: @@ -727,7 +740,7 @@ def snap(self,mode="None"): self.status("Snap failed :(") self.log.critical("snap: snapshot file doesn't exists: %s"%snap_filename) self.image.unload() - except Exception, e: + except Exception as e: #traceback.print_exc() self.log.exception("snap: error during snapshot") @@ -965,7 +978,8 @@ def send_print(self): try: conn = cups.Connection() printers = conn.getPrinters() - default_printer = printers.keys()[self.selected_printer]#defaults to the first printer installed + printer_index = int(self.selected_printer) #defaults to the first printer installed + default_printer = list(printers.keys())[printer_index] cups.setUser(getpass.getuser()) conn.printFile(default_printer, self.last_picture_filename, self.last_picture_title, {'fit-to-page':'True'}) self.log.info('send_print: Sending to printer...') @@ -998,7 +1012,7 @@ def __send_picture(self): config.emailSubject, config.emailMsg, self.last_picture_filename) - except Exception, e: + except Exception as e: self.log.exception('send_picture: Mail sending Failed') self.status("Send failed :(") retcode = False @@ -1092,7 +1106,8 @@ def mod_effect(): top.rowconfigure(NROWS+1, weight=1) self.root.wait_window(top) - + + if __name__ == '__main__': import argparse