def __init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable = False self.sw = StopWatch() self.sw.off() self.mon.trace(self, '') # and initilise things for this player # get duration from profile if self.track_params['duration'] != "": self.duration = int(self.track_params['duration']) else: self.duration = int(self.show_params['duration']) self.html_message_text_obj = None self.track_obj = None # initialise the state machine self.play_state = 'initialised'
def __init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable = False self.sw = StopWatch() self.sw.off() self.mon.trace(self, '') # and initialise things for this player # print 'imageplayer init' # get duration from profile if self.track_params['duration'] != '': self.duration = int(self.track_params['duration']) else: self.duration = int(self.show_params['duration']) # get image window from profile if self.track_params['image-window'].strip() != '': self.image_window = self.track_params['image-window'].strip() else: self.image_window = self.show_params['image-window'].strip() # get image rotation from profile if self.track_params['image-rotate'].strip() != '': self.image_rotate = int(self.track_params['image-rotate'].strip()) else: self.image_rotate = int(self.show_params['image-rotate'].strip()) if self.track_params['pause-timeout'] != '': pause_timeout_text = self.track_params['pause-timeout'] else: pause_timeout_text = self.show_params['pause-timeout'] if pause_timeout_text.isdigit(): self.pause_timeout = int(pause_timeout_text) else: self.pause_timeout = 0 self.track_image_obj = None self.tk_img = None self.paused = False self.pause_text_obj = None self.pause_timer = None # initialise the state machine self.play_state = 'initialised'
def __init__(self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__( self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable=False self.sw=StopWatch() self.sw.off() self.mon.trace(self,'') # and initilise things for this player # get duration from profile if self.track_params['duration'] != "": self.duration= int(self.track_params['duration']) else: self.duration= int(self.show_params['duration']) # initialise the state machine self.play_state='initialised'
class ImagePlayer(Player): """ Displays an image on a canvas for a period of time. Image display can be paused and interrupted __init_ just makes sure that all the things the player needs are available load and unload loads and unloads the track show shows the track,close closes the track after pause at end input-pressed receives user input while the track is playing. """ def __init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable = False self.sw = StopWatch() self.sw.off() self.mon.trace(self, '') # and initialise things for this player # print 'imageplayer init' # get duration from profile if self.track_params['duration'] != '': self.duration = int(self.track_params['duration']) else: self.duration = int(self.show_params['duration']) # get image window from profile if self.track_params['image-window'].strip() != '': self.image_window = self.track_params['image-window'].strip() else: self.image_window = self.show_params['image-window'].strip() # get image rotation from profile if self.track_params['image-rotate'].strip() != '': self.image_rotate = int(self.track_params['image-rotate'].strip()) else: self.image_rotate = int(self.show_params['image-rotate'].strip()) self.track_image_obj = None self.tk_img = None # krt 28/1/2016 self.paused = False self.pause_text_obj = None # initialise the state machine self.play_state = 'initialised' # LOAD - loads the images and text def load(self, track, loaded_callback, enable_menu): # instantiate arguments self.track = track # print 'imageplayer load',self.track self.loaded_callback = loaded_callback # callback when loaded self.mon.trace(self, '') Player.pre_load(self) # parse the image_window status, message, self.command, self.has_coords, self.window_x1, self.window_y1, self.window_x2, self.window_y2, self.image_filter = self.parse_window( self.image_window) if status == 'error': self.mon.err( self, 'image window error, ' + message + ': ' + self.image_window) self.play_state = 'load-failed' self.loaded_callback( 'error', 'image window error, ' + message + ': ' + self.image_window) return # load the plugin, this may modify self.track and enable the plugin drawing to canvas if self.track_params['plugin'] != '': status, message = self.load_plugin() if status == 'error': self.mon.err(self, message) self.play_state = 'load-failed' self.loaded_callback('error', message) return # load the images and text status, message = Player.load_x_content(self, enable_menu) if status == 'error': self.mon.err(self, message) self.play_state = 'load-failed' self.loaded_callback('error', message) return else: self.play_state = 'loaded' if self.loaded_callback is not None: self.loaded_callback('loaded', 'image track loaded') # UNLOAD - abort a load when sub-process is loading or loaded def unload(self): self.mon.trace(self, '') # nothing to do for imageplayer self.mon.log(self, ">unload received from show Id: " + str(self.show_id)) self.play_state = 'unloaded' # SHOW - show a track from its loaded state def show(self, ready_callback, finished_callback, closed_callback): # instantiate arguments self.ready_callback = ready_callback # callback when ready to show an image - self.finished_callback = finished_callback # callback when finished showing self.closed_callback = closed_callback # callback when closed - not used by imageplayer self.mon.trace(self, '') # init state and signals self.tick = 100 # tick time for image display (milliseconds) self.dwell = 10 * self.duration self.dwell_counter = 0 self.quit_signal = False self.paused = False self.pause_text_obj = None # do common bits Player.pre_show(self) # start show state machine self.start_dwell() # CLOSE - nothing to do in imageplayer - x content is removed by ready callback and hide def close(self, closed_callback): self.mon.trace(self, '') self.closed_callback = closed_callback self.mon.log(self, ">close received from show Id: " + str(self.show_id)) if self.tick_timer != None: self.canvas.after_cancel(self.tick_timer) self.play_state = 'closed' if self.closed_callback is not None: self.closed_callback('normal', 'imageplayer closed') def input_pressed(self, symbol): self.mon.trace(self, symbol) if symbol == 'pause': self.pause() if symbol == 'pause-on': self.pause_on() if symbol == 'pause-off': self.pause_off() elif symbol == 'stop': self.stop() def pause(self): if not self.paused: self.paused = True else: self.paused = False def pause_on(self): self.paused = True def pause_off(self): self.paused = False def stop(self): self.quit_signal = True # ****************************************** # Sequencing # ******************************************** def start_dwell(self): self.play_state = 'showing' self.tick_timer = self.canvas.after(self.tick, self.do_dwell) def do_dwell(self): if self.quit_signal is True: self.mon.log(self, "quit received") if self.finished_callback is not None: self.finished_callback('pause_at_end', 'user quit or duration exceeded') # use finish so that the show will call close else: if self.paused is False: self.dwell_counter = self.dwell_counter + 1 # one time flipping of pause text pause_text = self.track_params['pause-text'] if self.paused is True and self.pause_text_obj is None: x, y, anchor, justify = calculate_text_position( self.track_params['pause-text-x'], self.track_params['pause-text-y'], self.show_canvas_x1, self.show_canvas_y1, self.show_canvas_centre_x, self.show_canvas_centre_y, self.show_canvas_x2, self.show_canvas_y2, self.track_params['pause-text-justify']) self.pause_text_obj = self.canvas.create_text( x, y, anchor=anchor, justify=justify, text=pause_text, fill=self.track_params['pause-text-colour'], font=self.track_params['pause-text-font']) self.canvas.update_idletasks() if self.paused is False and self.pause_text_obj is not None: self.canvas.delete(self.pause_text_obj) self.pause_text_obj = None self.canvas.update_idletasks() if self.dwell != 0 and self.dwell_counter == self.dwell: if self.finished_callback is not None: self.finished_callback('pause_at_end', 'user quit or duration exceeded') # use finish so that the show will call close else: self.tick_timer = self.canvas.after(self.tick, self.do_dwell) # ***************** # x content # ***************** # called from Player, load_x_content def load_track_content(self): ppil_image = None # Keep landscape happy # get the track to be displayed if os.path.exists(self.track) is True: try: ppil_image = Image.open(self.track) except: ppil_image = None self.tk_img = None self.track_image_obj = None return 'error', 'Not a recognised image format ' + self.track else: ppil_image = None self.tk_img = None self.track_image_obj = None return 'error', 'Track file not found ' + self.track # display track image if ppil_image is not None: #rotate the image # print self.image_width,self.image_height if self.image_rotate != 0: ppil_image = ppil_image.rotate(self.image_rotate, expand=True) self.image_width, self.image_height = ppil_image.size # print self.image_width,self.image_height if self.command == 'original': # display image at its original size if self.has_coords is False: # load and display the unmodified image in centre self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( self.show_canvas_centre_x + self.show_canvas_x1, self.show_canvas_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) else: # load and display the unmodified image at x1,y1 self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( self.window_x1 + self.show_canvas_x1, self.window_y1 + self.show_canvas_y1, image=self.tk_img, anchor=NW) elif self.command in ('fit', 'shrink'): # shrink fit the window or screen preserving aspect if self.has_coords is True: window_width = self.window_x2 - self.window_x1 window_height = self.window_y2 - self.window_y1 window_centre_x = (self.window_x2 + self.window_x1) / 2 window_centre_y = (self.window_y2 + self.window_y1) / 2 else: window_width = self.show_canvas_width window_height = self.show_canvas_height window_centre_x = self.show_canvas_centre_x window_centre_y = self.show_canvas_centre_y if (self.image_width > window_width or self.image_height > window_height and self.command == 'fit') or (self.command == 'shrink'): # print 'show canvas',self.show_canvas_x1,self.show_canvas_y1,self.show_canvas_x2,self.show_canvas_y2 # print 'canvas width/height/centre',self.show_canvas_width,self.show_canvas_height,self.show_canvas_centre_x,self.show_canvas_centre_y # print 'window dimensions/centre',window_width,window_height,window_centre_x,window_centre_y # print # original image is larger or , shrink it to fit the screen preserving aspect ppil_image.thumbnail( (int(window_width), int(window_height)), eval(self.image_filter)) self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) else: # fitting and original image is smaller, expand it to fit the screen preserving aspect prop_x = float(window_width) / self.image_width prop_y = float(window_height) / self.image_height if prop_x > prop_y: prop = prop_y else: prop = prop_x increased_width = int(self.image_width * prop) increased_height = int(self.image_height * prop) # print 'result',prop, increased_width,increased_height ppil_image = ppil_image.resize( (int(increased_width), int(increased_height)), eval(self.image_filter)) self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) elif self.command in ('warp'): # resize to window or screen without preserving aspect if self.has_coords is True: window_width = self.window_x2 - self.window_x1 window_height = self.window_y2 - self.window_y1 window_centre_x = (self.window_x2 + self.window_x1) / 2 window_centre_y = (self.window_y2 + self.window_y1) / 2 else: window_width = self.show_canvas_width window_height = self.show_canvas_height window_centre_x = self.show_canvas_centre_x window_centre_y = self.show_canvas_centre_y # print 'window',window_width,window_height,window_centre_x,window_centre_y,self.show_canvas_x1,self.show_canvas_y1,'\n' ppil_image = ppil_image.resize( (int(window_width), int(window_height)), eval(self.image_filter)) self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) self.canvas.itemconfig(self.track_image_obj, state='hidden') return 'normal', 'track content loaded' def show_track_content(self): self.canvas.itemconfig(self.track_image_obj, state='normal') def hide_track_content(self): if self.pause_text_obj is not None: self.canvas.delete(self.pause_text_obj) self.pause_text_obj = None # self.canvas.update_idletasks( ) self.canvas.itemconfig(self.track_image_obj, state='hidden') self.canvas.delete(self.track_image_obj) self.tk_img = None def parse_window(self, line): fields = line.split() # check there is a command field if len(fields) < 1: return 'error', 'No command field', '', False, 0, 0, 0, 0, '' # deal with original whch has 0 or 2 arguments image_filter = '' if fields[0] == 'original': if len(fields) not in (1, 3): return 'error', 'Original has wrong number of arguments', '', False, 0, 0, 0, 0, '' # deal with window coordinates if len(fields) == 3: # window is specified if not (fields[1].isdigit() and fields[2].isdigit()): return 'error', 'coordinates are not numbers', '', False, 0, 0, 0, 0, '' has_window = True return 'normal', '', fields[0], has_window, float( fields[1]), float(fields[2]), 0, 0, image_filter else: # no window has_window = False return 'normal', '', fields[ 0], has_window, 0, 0, 0, 0, image_filter # deal with remainder which has 1, 2, 5 or 6arguments # check basic syntax if fields[0] not in ('shrink', 'fit', 'warp'): return 'error', 'illegal command' + fields[ 0], '', False, 0, 0, 0, 0, '' if len(fields) not in (1, 2, 3, 5, 6): return 'error', 'wrong number of fields' + str( len(fields)), '', False, 0, 0, 0, 0, '' if len(fields) == 6 and fields[5] not in ('NEAREST', 'BILINEAR', 'BICUBIC', 'ANTIALIAS'): return 'error', 'wrong filter or params' + fields[ 5], '', False, 0, 0, 0, 0, '' if len(fields) == 2 and (fields[1] not in ('NEAREST', 'BILINEAR', 'BICUBIC', 'ANTIALIAS') and '*' not in fields[1]): return 'error', 'wrong filter or params' + fields[ 1], '', False, 0, 0, 0, 0, '' if len(fields) == 3 and fields[2] not in ('NEAREST', 'BILINEAR', 'BICUBIC', 'ANTIALIAS'): return 'error', 'wrong filter or params' + fields[ 2], '', False, 0, 0, 0, 0, '' # deal with no window coordinates and no if len(fields) == 1: has_window = False return 'normal', '', fields[ 0], has_window, 0, 0, 0, 0, 'Image.NEAREST' # deal with window coordinates in +* format with optional filter if len(fields) in (2, 3) and '*' in fields[1]: status, message, x1, y1, x2, y2 = parse_rectangle(fields[1]) if status == 'error': return 'error', message, '', False, 0, 0, 0, 0, '' else: has_window = True if len(fields) == 3: image_filter = 'Image.' + fields[2] else: image_filter = 'Image.NEAREST' return 'normal', '', fields[ 0], has_window, x1, y1, x2, y2, image_filter if len(fields) in (5, 6): # window is specified in x1 y1 x2 y2 if not (fields[1].isdigit() and fields[2].isdigit() and fields[3].isdigit() and fields[4].isdigit()): return 'error', 'coords are not numbers', '', False, 0, 0, 0, 0, '' has_window = True if len(fields) == 6: image_filter = 'Image.' + fields[5] else: image_filter = 'Image.NEAREST' return 'normal', '', fields[0], has_window, float( fields[1]), float(fields[2]), float(fields[3]), float( fields[4]), image_filter else: # no window has_window = False if len(fields) == 2: image_filter = 'Image.' + fields[1] else: image_filter = 'Image.NEAREST' return 'normal', '', fields[ 0], has_window, 0, 0, 0, 0, image_filter
class MessagePlayer(Player): """ Displays a message on a canvas for a period of time. Message display can be interrupted Differs from other players in that text is passed as parameter rather than file containing the text __init_ just makes sure that all the things the player needs are available load and unload loads and unloads the track show shows the track,close closes the track after pause at end input-pressed receives user input while the track is playing. """ def __init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable = False self.sw = StopWatch() self.sw.off() self.mon.trace(self, '') # and initilise things for this player # get duration from profile if self.track_params['duration'] != "": self.duration = int(self.track_params['duration']) else: self.duration = int(self.show_params['duration']) self.html_message_text_obj = None self.track_obj = None # initialise the state machine self.play_state = 'initialised' # LOAD - loads the images and text def load(self, text, loaded_callback, enable_menu): # instantiate arguments self.track = text self.loaded_callback = loaded_callback # callback when loaded self.mon.trace(self, '') # do common bits of load Player.pre_load(self) # load the plugin, this may modify self.track and enable the plugin drawing to canvas if self.track_params['plugin'] != '': status, message = self.load_plugin() # can modify self.track with new text, does not touch message location if status == 'error': self.mon.err(self, message) self.play_state = 'load-failed' if self.loaded_callback is not None: self.loaded_callback('error', message) return # load the images and text including message text status, message = self.load_x_content(enable_menu) if status == 'error': self.mon.err(self, message) self.play_state = 'load-failed' if self.loaded_callback is not None: self.loaded_callback('error', message) return else: self.play_state = 'loaded' if self.loaded_callback is not None: self.loaded_callback('loaded', 'message track loaded') # UNLOAD - abort a load when omplayer is loading or loaded def unload(self): self.mon.trace(self, '') # nothing to do for Messageplayer self.mon.log(self, ">unload received from show Id: " + str(self.show_id)) self.play_state = 'unloaded' # SHOW - show a track from its loaded state def show(self, ready_callback, finished_callback, closed_callback): # instantiate arguments self.ready_callback = ready_callback # callback when ready to show an image - self.finished_callback = finished_callback # callback when finished showing self.closed_callback = closed_callback # callback when closed - not used by Messageplayer self.mon.trace(self, '') # init state and signals self.tick = 100 # tick time for image display (milliseconds) self.dwell = 10 * self.duration self.dwell_counter = 0 self.quit_signal = False # do common bits Player.pre_show(self) # start show state machine self.start_dwell() # CLOSE - nothing to do in messageplayer - x content is removed by ready callback def close(self, closed_callback): self.mon.trace(self, '') self.closed_callback = closed_callback self.mon.log(self, ">close received from show Id: " + str(self.show_id)) if self.tick_timer != None: self.canvas.after_cancel(self.tick_timer) self.play_state = 'closed' if self.closed_callback is not None: self.closed_callback('normal', 'Messageplayer closed') def input_pressed(self, symbol): if symbol == 'stop': self.stop() def stop(self): self.quit_signal = True # ****************************************** # Sequencing # ******************************************** def start_dwell(self): self.play_state = 'showing' self.tick_timer = self.canvas.after(self.tick, self.do_dwell) def do_dwell(self): if self.quit_signal is True: self.mon.log(self, "quit received") if self.finished_callback is not None: self.finished_callback('pause_at_end', 'user quit or duration exceeded') # use finish so that the show will call close else: self.dwell_counter = self.dwell_counter + 1 if self.dwell != 0 and self.dwell_counter == self.dwell: if self.finished_callback is not None: self.finished_callback('pause_at_end', 'user quit or duration exceeded') # use finish and pause_at_end so that the show will call close else: self.tick_timer = self.canvas.after(self.tick, self.do_dwell) # ***************** # x content # ***************** # called from Player, load_x_content def load_track_content(self): # load message text # print 'show canvas',self.show_canvas_x1,self.show_canvas_y1,self.show_canvas_x2,self.show_canvas_y2 # print 'canvas width/height/centre',self.show_canvas_width,self.show_canvas_height,self.show_canvas_centre_x,self.show_canvas_centre_y # print self.message_html_background_colour = self.track_params[ 'message-html-background-colour'] if self.track_params['message-html-width'] == '': self.message_html_width = self.show_canvas_x2 - self.show_canvas_x1 else: self.message_html_width = self.track_params['message-html-width'] if self.track_params['message-html-height'] == '': self.message_html_height = self.show_canvas_y2 - self.show_canvas_y1 else: self.message_html_height = self.track_params['message-html-height'] self.message_text_type = self.track_params['message-text-type'] if self.track_params['message-text-location'] != '': text_path = self.complete_path( self.track_params['message-text-location']) if not os.path.exists(text_path): return 'error', "Message Text file not found " + text_path with open(text_path) as f: message_text = f.read() else: message_text = self.track x, y, anchor, justify = calculate_text_position( self.track_params['message-x'], self.track_params['message-y'], self.show_canvas_x1, self.show_canvas_y1, self.show_canvas_centre_x, self.show_canvas_centre_y, self.show_canvas_x2, self.show_canvas_y2, self.track_params['message-justify']) if self.message_text_type == 'html': self.html_message_text_obj = HTMLText( self.canvas, background=self.message_html_background_colour, relief=FLAT) # self.html_text.pack(fill="both", expand=True) self.html_message_text_obj.set_html(message_text, self.pp_home, self.pp_profile) # self.html_text.fit_height() self.track_obj = self.canvas.create_window( x, y, window=self.html_message_text_obj, anchor=anchor, width=self.message_html_width, height=self.message_html_height) else: self.track_obj = self.canvas.create_text( x, y, text=message_text.rstrip('\n'), fill=self.track_params['message-colour'], font=self.track_params['message-font'], justify=justify, anchor=anchor) self.canvas.itemconfig(self.track_obj, state='hidden') return 'normal', 'message loaded' def show_track_content(self): self.canvas.itemconfig(self.track_obj, state='normal') def hide_track_content(self): if self.track_obj != None: self.canvas.itemconfig(self.track_obj, state='hidden') if self.html_message_text_obj != None: self.html_message_text_obj.delete_parser() self.canvas.delete(self.track_obj)
def __init__(self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__( self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable=False self.sw=StopWatch() self.sw.off() self.mon.trace(self,'') # and initialise things for this player # print 'imageplayer init' # get duration from profile if self.track_params['duration'] != '': self.duration= int(self.track_params['duration']) else: self.duration= int(self.show_params['duration']) # get image window from profile if self.track_params['image-window'].strip() != '': self.image_window= self.track_params['image-window'].strip() else: self.image_window= self.show_params['image-window'].strip() # get image rotation from profile if self.track_params['image-rotate'].strip() != '': self.image_rotate = int(self.track_params['image-rotate'].strip()) else: self.image_rotate= int(self.show_params['image-rotate'].strip()) self.track_image_obj=None self.tk_img=None # krt 28/1/2016 self.paused=False self.pause_text_obj=None # initialise the state machine self.play_state='initialised'
class ImagePlayer(Player): """ Displays an image on a canvas for a period of time. Image display can be paused and interrupted __init_ just makes sure that all the things the player needs are available load and unload loads and unloads the track show shows the track,close closes the track after pause at end input-pressed receives user input while the track is playing. """ def __init__(self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__( self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable=False self.sw=StopWatch() self.sw.off() self.mon.trace(self,'') # and initialise things for this player # print 'imageplayer init' # get duration from profile if self.track_params['duration'] != '': self.duration= int(self.track_params['duration']) else: self.duration= int(self.show_params['duration']) # get image window from profile if self.track_params['image-window'].strip() != '': self.image_window= self.track_params['image-window'].strip() else: self.image_window= self.show_params['image-window'].strip() # get image rotation from profile if self.track_params['image-rotate'].strip() != '': self.image_rotate = int(self.track_params['image-rotate'].strip()) else: self.image_rotate= int(self.show_params['image-rotate'].strip()) self.track_image_obj=None self.tk_img=None # krt 28/1/2016 self.paused=False self.pause_text_obj=None # initialise the state machine self.play_state='initialised' # LOAD - loads the images and text def load(self,track,loaded_callback,enable_menu): # instantiate arguments self.track=track # print 'imageplayer load',self.track self.loaded_callback=loaded_callback # callback when loaded self.mon.trace(self,'') Player.pre_load(self) # parse the image_window status,self.command,self.has_coords,self.window_x1,self.window_y1,self.window_x2,self.window_y2,self.image_filter=self.parse_window(self.image_window) if status == 'error': self.mon.err(self,'image window error: '+self.image_window) self.play_state='load-failed' self.loaded_callback('error','image window error: '+self.image_window) return # load the plugin, this may modify self.track and enable the plugin drawing to canvas if self.track_params['plugin'] != '': status,message=self.load_plugin() if status == 'error': self.mon.err(self,message) self.play_state='load-failed' self.loaded_callback('error',message) return # load the images and text status,message=Player.load_x_content(self,enable_menu) if status == 'error': self.mon.err(self,message) self.play_state='load-failed' self.loaded_callback('error',message) return else: self.play_state='loaded' if self.loaded_callback is not None: self.loaded_callback('loaded','image track loaded') # UNLOAD - abort a load when sub-process is loading or loaded def unload(self): self.mon.trace(self,'') # nothing to do for imageplayer self.mon.log(self,">unload received from show Id: "+ str(self.show_id)) self.play_state='unloaded' # SHOW - show a track from its loaded state def show(self,ready_callback,finished_callback,closed_callback): # instantiate arguments self.ready_callback=ready_callback # callback when ready to show an image - self.finished_callback=finished_callback # callback when finished showing self.closed_callback=closed_callback # callback when closed - not used by imageplayer self.mon.trace(self,'') # init state and signals self.tick = 100 # tick time for image display (milliseconds) self.dwell = 10*self.duration self.dwell_counter=0 self.quit_signal=False self.paused=False self.pause_text_obj=None # do common bits Player.pre_show(self) # start show state machine self.start_dwell() # CLOSE - nothing to do in imageplayer - x content is removed by ready callback and hide def close(self,closed_callback): self.mon.trace(self,'') self.closed_callback=closed_callback self.mon.log(self,">close received from show Id: "+ str(self.show_id)) if self.tick_timer!= None: self.canvas.after_cancel(self.tick_timer) self.play_state='closed' if self.closed_callback is not None: self.closed_callback('normal','imageplayer closed') def input_pressed(self,symbol): self.mon.trace(self,symbol) if symbol == 'pause': self.pause() elif symbol == 'stop': self.stop() def pause(self): if not self.paused: self.paused = True else: self.paused=False def stop(self): self.quit_signal=True # ****************************************** # Sequencing # ******************************************** def start_dwell(self): self.play_state='showing' self.tick_timer=self.canvas.after(self.tick, self.do_dwell) def do_dwell(self): if self.quit_signal is True: self.mon.log(self,"quit received") if self.finished_callback is not None: self.finished_callback('pause_at_end','user quit or duration exceeded') # use finish so that the show will call close else: if self.paused is False: self.dwell_counter=self.dwell_counter+1 # one time flipping of pause text pause_text= self.track_params['pause-text'] if self.paused is True and self.pause_text_obj is None: self.pause_text_obj=self.canvas.create_text(self.track_params['pause-text-x'],self.track_params['pause-text-y'], anchor=NW, text=pause_text, fill=self.track_params['pause-text-colour'], font=self.track_params['pause-text-font']) self.canvas.update_idletasks( ) if self.paused is False and self.pause_text_obj is not None: self.hide_plugin() self.canvas.delete(self.pause_text_obj) self.pause_text_obj=None self.canvas.update_idletasks( ) if self.dwell != 0 and self.dwell_counter == self.dwell: if self.finished_callback is not None: self.finished_callback('pause_at_end','user quit or duration exceeded') # use finish so that the show will call close else: self.tick_timer=self.canvas.after(self.tick, self.do_dwell) # ***************** # x content # ***************** # called from Player, load_x_content def load_track_content(self): ppil_image=None # Keep landscape happy # get the track to be displayed if os.path.exists(self.track) is True: ppil_image=Image.open(self.track) else: ppil_image=None self.tk_img=None self.track_image_obj=None return 'error','Track file not found '+ self.track # display track image if ppil_image is not None: #rotate the image # print self.image_width,self.image_height if self.image_rotate!=0: ppil_image=ppil_image.rotate(self.image_rotate,expand=True) self.image_width,self.image_height=ppil_image.size # print self.image_width,self.image_height if self.command == 'original': # display image at its original size if self.has_coords is False: # load and display the unmodified image in centre self.tk_img=ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image(self.show_canvas_centre_x+self.show_canvas_x1, self.show_canvas_centre_y+self.show_canvas_y1, image=self.tk_img, anchor=CENTER) else: # load and display the unmodified image at x1,y1 self.tk_img=ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image(self.window_x1+self.show_canvas_x1, self.window_y1+self.show_canvas_y1, image=self.tk_img, anchor=NW) elif self.command in ('fit','shrink'): # shrink fit the window or screen preserving aspect if self.has_coords is True: window_width=self.window_x2 - self.window_x1 window_height=self.window_y2 - self.window_y1 window_centre_x=(self.window_x2+self.window_x1)/2 window_centre_y= (self.window_y2+self.window_y1)/2 else: window_width=self.show_canvas_width window_height=self.show_canvas_height window_centre_x=self.show_canvas_centre_x window_centre_y=self.show_canvas_centre_y if (self.image_width > window_width or self.image_height > window_height and self.command == 'fit') or (self.command == 'shrink') : # print 'show canvas',self.show_canvas_x1,self.show_canvas_y1,self.show_canvas_x2,self.show_canvas_y2 # print 'canvas width/height/centre',self.show_canvas_width,self.show_canvas_height,self.show_canvas_centre_x,self.show_canvas_centre_y # print 'window dimensions/centre',window_width,window_height,window_centre_x,window_centre_y # print # original image is larger or , shrink it to fit the screen preserving aspect ppil_image.thumbnail((int(window_width),int(window_height)),eval(self.image_filter)) self.tk_img=ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image(window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) else: # fitting and original image is smaller, expand it to fit the screen preserving aspect prop_x = float(window_width) / self.image_width prop_y = float(window_height) / self.image_height if prop_x > prop_y: prop=prop_y else: prop=prop_x increased_width=int(self.image_width * prop) increased_height=int(self.image_height * prop) # print 'result',prop, increased_width,increased_height ppil_image=ppil_image.resize((int(increased_width), int(increased_height)),eval(self.image_filter)) self.tk_img=ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image(window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) elif self.command in ('warp'): # resize to window or screen without preserving aspect if self.has_coords is True: window_width=self.window_x2 - self.window_x1 window_height=self.window_y2 - self.window_y1 window_centre_x=(self.window_x2+self.window_x1)/2 window_centre_y= (self.window_y2+self.window_y1)/2 else: window_width=self.show_canvas_width window_height=self.show_canvas_height window_centre_x=self.show_canvas_centre_x window_centre_y=self.show_canvas_centre_y # print 'window',window_width,window_height,window_centre_x,window_centre_y,self.show_canvas_x1,self.show_canvas_y1,'\n' ppil_image=ppil_image.resize((int(window_width), int(window_height)),eval(self.image_filter)) self.tk_img=ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image(window_centre_x+ self.show_canvas_x1, window_centre_y+ self.show_canvas_y1, image=self.tk_img, anchor=CENTER) self.canvas.itemconfig(self.track_image_obj,state='hidden') return 'normal','track content loaded'; def show_track_content(self): self.canvas.itemconfig(self.track_image_obj,state='normal') def hide_track_content(self): if self.pause_text_obj is not None: self.canvas.delete(self.pause_text_obj) self.pause_text_obj=None # self.canvas.update_idletasks( ) self.canvas.itemconfig(self.track_image_obj,state='hidden') self.canvas.delete(self.track_image_obj) self.tk_img=None def parse_window(self,line): fields = line.split() # check there is a command field if len(fields) < 1: return 'error','',False,0,0,0,0,'' # deal with original whch has 0 or 2 arguments image_filter='' if fields[0] == 'original': if len(fields) not in (1,3): return 'error','',False,0,0,0,0,'' # deal with window coordinates if len(fields) == 3: # window is specified if not (fields[1].isdigit() and fields[2].isdigit()): return 'error','',False,0,0,0,0,'' has_window=True return 'normal',fields[0],has_window,float(fields[1]),float(fields[2]),0,0,image_filter else: # no window has_window=False return 'normal',fields[0],has_window,0,0,0,0,image_filter # deal with remainder which has 1, 2, 5 or 6arguments # check basic syntax if fields[0] not in ('shrink','fit','warp'): return 'error','',False,0,0,0,0,'' if len(fields) not in (1,2,5,6): return 'error','',False,0,0,0,0,'' if len(fields) == 6 and fields[5] not in ('NEAREST','BILINEAR','BICUBIC','ANTIALIAS'): return 'error','',False,0,0,0,0,'' if len(fields) == 2 and fields[1] not in ('NEAREST','BILINEAR','BICUBIC','ANTIALIAS'): return 'error','',False,0,0,0,0,'' # deal with window coordinates if len(fields) in (5,6): # window is specified if not (fields[1].isdigit() and fields[2].isdigit() and fields[3].isdigit() and fields[4].isdigit()): return 'error','',False,0,0,0,0,'' has_window=True if len(fields) == 6: image_filter=fields[5] else: image_filter='Image.NEAREST' return 'normal',fields[0],has_window,float(fields[1]),float(fields[2]),float(fields[3]),float(fields[4]),image_filter else: # no window has_window=False if len(fields) == 2: image_filter=fields[1] else: image_filter='Image.NEAREST' return 'normal',fields[0],has_window,0,0,0,0,image_filter
class MessagePlayer(Player): """ Displays a message on a canvas for a period of time. Message display can be interrupted Differs from other players in that text is passed as parameter rather than file containing the text __init_ just makes sure that all the things the player needs are available load and unload loads and unloads the track show shows the track,close closes the track after pause at end input-pressed receives user input while the track is playing. """ def __init__(self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__( self, show_id, showlist, root, canvas, show_params, track_params , pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable=False self.sw=StopWatch() self.sw.off() self.mon.trace(self,'') # and initilise things for this player # get duration from profile if self.track_params['duration'] != "": self.duration= int(self.track_params['duration']) else: self.duration= int(self.show_params['duration']) # initialise the state machine self.play_state='initialised' # LOAD - loads the images and text def load(self,text,loaded_callback,enable_menu): # instantiate arguments self.track=text self.loaded_callback=loaded_callback # callback when loaded self.mon.trace(self,'') # do common bits of load Player.pre_load(self) # load the plugin, this may modify self.ttack and enable the plugin drawign to canvas if self.track_params['plugin'] != '': status,message=self.load_plugin() if status == 'error': self.mon.err(self,message) self.play_state='load-failed' if self.loaded_callback is not None: self.loaded_callback('error',message) return # load the images and text including message text status,message=self.load_x_content(enable_menu) if status == 'error': self.mon.err(self,message) self.play_state='load-failed' if self.loaded_callback is not None: self.loaded_callback('error',message) return else: self.play_state='loaded' if self.loaded_callback is not None: self.loaded_callback('loaded','message track loaded') # UNLOAD - abort a load when omplayer is loading or loaded def unload(self): self.mon.trace(self,'') # nothing to do for Messageplayer self.mon.log(self,">unload received from show Id: "+ str(self.show_id)) self.play_state='unloaded' # SHOW - show a track from its loaded state def show(self,ready_callback,finished_callback,closed_callback): # instantiate arguments self.ready_callback=ready_callback # callback when ready to show an image - self.finished_callback=finished_callback # callback when finished showing self.closed_callback=closed_callback # callback when closed - not used by Messageplayer self.mon.trace(self,'') # init state and signals self.tick = 100 # tick time for image display (milliseconds) self.dwell = 10*self.duration self.dwell_counter=0 self.quit_signal=False # do common bits Player.pre_show(self) # start show state machine self.start_dwell() # CLOSE - nothing to do in messageplayer - x content is removed by ready callback def close(self,closed_callback): self.mon.trace(self,'') self.closed_callback=closed_callback self.mon.log(self,">close received from show Id: "+ str(self.show_id)) if self.tick_timer!= None: self.canvas.after_cancel(self.tick_timer) self.play_state='closed' if self.closed_callback is not None: self.closed_callback('normal','Messageplayer closed') def input_pressed(self,symbol): if symbol == 'stop': self.stop() def stop(self): self.quit_signal=True # ****************************************** # Sequencing # ******************************************** def start_dwell(self): self.play_state='showing' self.tick_timer=self.canvas.after(self.tick, self.do_dwell) def do_dwell(self): if self.quit_signal is True: self.mon.log(self,"quit received") if self.finished_callback is not None: self.finished_callback('pause_at_end','user quit or duration exceeded') # use finish so that the show will call close else: self.dwell_counter=self.dwell_counter+1 if self.dwell != 0 and self.dwell_counter == self.dwell: if self.finished_callback is not None: self.finished_callback('pause_at_end','user quit or duration exceeded') # use finish and pause_at_end so that the show will call close else: self.tick_timer=self.canvas.after(self.tick, self.do_dwell) # ***************** # x content # ***************** # called from Player, load_x_content def load_track_content(self): # load message text # print 'show canvas',self.show_canvas_x1,self.show_canvas_y1,self.show_canvas_x2,self.show_canvas_y2 # print 'canvas width/height/centre',self.show_canvas_width,self.show_canvas_height,self.show_canvas_centre_x,self.show_canvas_centre_y # print x,y,anchor,justify=calculate_text_position(self.track_params['message-x'],self.track_params['message-y'], self.show_canvas_x1,self.show_canvas_y1, self.show_canvas_centre_x,self.show_canvas_centre_y, self.show_canvas_x2,self.show_canvas_y2,self.track_params['message-justify']) self.track_obj=self.canvas.create_text(x,y, text=self.track.rstrip('\n'), fill=self.track_params['message-colour'], font=self.track_params['message-font'], justify=justify, anchor = anchor) self.canvas.itemconfig(self.track_obj,state='hidden') return 'normal','message loaded' def show_track_content(self): self.canvas.itemconfig(self.track_obj,state='normal') def hide_track_content(self): self.canvas.itemconfig(self.track_obj,state='hidden') self.canvas.delete(self.track_obj)
class ImagePlayer(Player): """ Displays an image on a canvas for a period of time. Image display can be paused and interrupted __init_ just makes sure that all the things the player needs are available load and unload loads and unloads the track show shows the track,close closes the track after pause at end input-pressed receives user input while the track is playing. """ def __init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback): # initialise items common to all players Player.__init__(self, show_id, showlist, root, canvas, show_params, track_params, pp_dir, pp_home, pp_profile, end_callback, command_callback) # stopwatch for timing functions StopWatch.global_enable = False self.sw = StopWatch() self.sw.off() self.mon.trace(self, '') # and initialise things for this player # print 'imageplayer init' # get duration from profile if self.track_params['duration'] != '': self.duration = int(self.track_params['duration']) else: self.duration = int(self.show_params['duration']) # get image window from profile if self.track_params['image-window'].strip() != '': self.image_window = self.track_params['image-window'].strip() else: self.image_window = self.show_params['image-window'].strip() # get image rotation from profile if self.track_params['image-rotate'].strip() != '': self.image_rotate = int(self.track_params['image-rotate'].strip()) else: self.image_rotate = int(self.show_params['image-rotate'].strip()) if self.track_params['pause-timeout'] != '': pause_timeout_text = self.track_params['pause-timeout'] else: pause_timeout_text = self.show_params['pause-timeout'] if pause_timeout_text.isdigit(): self.pause_timeout = int(pause_timeout_text) else: self.pause_timeout = 0 self.track_image_obj = None self.tk_img = None self.paused = False self.pause_text_obj = None self.pause_timer = None # initialise the state machine self.play_state = 'initialised' def read_tags(self, image): """ Reads the tags from the EXIF data in the image and returns them in a dictionary. :param image: Image to read tags from :return: Dictionary with human names as the index and tag values as the value, and a separate dictionary of the GPS tags """ dict = {} gps_dict = {} try: exif_tags = image._getexif() except: exif_tags = None if exif_tags: for tag, value in exif_tags.items(): decoded = TAGS.get(tag, tag) dict[decoded] = value if decoded == "GPSInfo": for t in value: sub_decoded = GPSTAGS.get(t, t) gps_dict[sub_decoded] = value[t] return dict, gps_dict def getplace(latitude, longitude): import json from urllib2 import urlopen url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=%s,%s&sensor=false" % ( latitude, longitude) v = urlopen(url).read() j = json.loads(v) components = j['results'][0]['address_components'] country = town = None for c in components: if "country" in c['types']: country = c['long_name'] if "postal_town" in c['types']: town = c['long_name'] return town, country def get_location(self, image): """ Read the location from the image, using EXIF data and a google lookup :param image: :return: string for the location, or None if not resolvable """ dict, gps_dict = self.read_tags(image) latitude = dictread(gps_dict, 'GPSLatitude', None) longitude = dictread(gps_dict, 'GPSLongitude', None) if latitude and longitude: return getplace(latitude, longitude) else: return None def rotate_image(self, image, orientation): """ Read the EXIF data, and rotate the image appropriately if needed :param image: :param orientation: :return: Original image, or a rotated image if appropriate. """ if orientation: if orientation == 3: image = image.rotate(180, expand=True) elif orientation == 6: image = image.rotate(270, expand=True) elif orientation == 8: image = image.rotate(90, expand=True) return image # LOAD - loads the images and text def load(self, track, loaded_callback, enable_menu): # instantiate arguments self.track = track # print 'imageplayer load',self.track self.loaded_callback = loaded_callback # callback when loaded self.mon.trace(self, '') Player.pre_load(self) # parse the image_window status, message, self.command, self.has_coords, self.window_x1, self.window_y1, self.window_x2, self.window_y2, self.image_filter = self.parse_window( self.image_window) if status == 'error': self.mon.err( self, 'image window error, ' + message + ': ' + self.image_window) self.play_state = 'load-failed' self.loaded_callback( 'error', 'image window error, ' + message + ': ' + self.image_window) return # load the plugin, this may modify self.track and enable the plugin drawing to canvas if self.track_params['plugin'] != '': status, message = self.load_plugin() if status == 'error': self.mon.err(self, message) self.play_state = 'load-failed' self.loaded_callback('error', message) return # load the images and text status, message = Player.load_x_content(self, enable_menu) if status == 'error': self.mon.err(self, message) self.play_state = 'load-failed' self.loaded_callback('error', message) return else: self.play_state = 'loaded' if self.loaded_callback is not None: self.loaded_callback('loaded', 'image track loaded') # UNLOAD - abort a load when sub-process is loading or loaded def unload(self): self.mon.trace(self, '') # nothing to do for imageplayer self.mon.log(self, ">unload received from show Id: " + str(self.show_id)) self.play_state = 'unloaded' # SHOW - show a track from its loaded state def show(self, ready_callback, finished_callback, closed_callback): # instantiate arguments self.ready_callback = ready_callback # callback when ready to show an image - self.finished_callback = finished_callback # callback when finished showing self.closed_callback = closed_callback # callback when closed - not used by imageplayer self.mon.trace(self, '') # init state and signals self.tick = 100 # tick time for image display (milliseconds) self.dwell = 10 * self.duration self.dwell_counter = 0 self.quit_signal = False self.paused = False self.pause_text_obj = None # do common bits Player.pre_show(self) # start show state machine self.start_dwell() # CLOSE - nothing to do in imageplayer - x content is removed by ready callback and hide def close(self, closed_callback): self.mon.trace(self, '') self.closed_callback = closed_callback self.mon.log(self, ">close received from show Id: " + str(self.show_id)) if self.tick_timer != None: self.canvas.after_cancel(self.tick_timer) self.play_state = 'closed' if self.closed_callback is not None: self.closed_callback('normal', 'imageplayer closed') def input_pressed(self, symbol): self.mon.trace(self, symbol) if symbol == 'pause': self.pause() if symbol == 'pause-on': self.pause_on() if symbol == 'pause-off': self.pause_off() elif symbol == 'stop': self.stop() def pause(self): if self.paused is False: self.paused = True if self.pause_timeout > 0: # kick off the pause teimeout timer print("!!toggle pause on") self.pause_timer = self.canvas.after( self.pause_timeout * 1000, self.pause_timeout_callback) else: self.paused = False # cancel the pause timer if self.pause_timer != None: print("!!toggle pause off") self.canvas.after_cancel(self.pause_timer) self.pause_timer = None def pause_timeout_callback(self): print("!!callback pause off") self.pause_off() self.pause_timer = None def pause_on(self): self.paused = True print("!!pause on") self.pause_timer = self.canvas.after(self.pause_timeout * 1000, self.pause_timeout_callback) def pause_off(self): self.paused = False print("!!pause off") # cancel the pause timer if self.pause_timer != None: self.canvas.after_cancel(self.pause_timer) self.pause_timer = None def stop(self): # cancel the pause timer if self.pause_timer != None: self.canvas.after_cancel(self.pause_timer) self.pause_timer = None self.quit_signal = True # ****************************************** # Sequencing # ******************************************** def start_dwell(self): self.play_state = 'showing' self.tick_timer = self.canvas.after(self.tick, self.do_dwell) def do_dwell(self): if self.quit_signal is True: self.mon.log(self, "quit received") if self.finished_callback is not None: self.finished_callback('pause_at_end', 'user quit or duration exceeded') # use finish so that the show will call close else: if self.paused is False: self.dwell_counter = self.dwell_counter + 1 # one time flipping of pause text pause_text = self.track_params['pause-text'] if self.paused is True and self.pause_text_obj is None: x, y, anchor, justify = calculate_text_position( self.track_params['pause-text-x'], self.track_params['pause-text-y'], self.show_canvas_x1, self.show_canvas_y1, self.show_canvas_centre_x, self.show_canvas_centre_y, self.show_canvas_x2, self.show_canvas_y2, self.track_params['pause-text-justify']) self.pause_text_obj = self.canvas.create_text( x, y, anchor=anchor, justify=justify, text=pause_text, fill=self.track_params['pause-text-colour'], font=self.track_params['pause-text-font']) self.canvas.update_idletasks() if self.paused is False and self.pause_text_obj is not None: self.canvas.delete(self.pause_text_obj) self.pause_text_obj = None self.canvas.update_idletasks() if self.dwell != 0 and self.dwell_counter == self.dwell: if self.finished_callback is not None: self.finished_callback('pause_at_end', 'user quit or duration exceeded') # use finish so that the show will call close else: self.tick_timer = self.canvas.after(self.tick, self.do_dwell) # ***************** # x content # ***************** # called from Player, load_x_content def load_track_content(self): ppil_image = None # Keep landscape happy # get the track to be displayed if os.path.exists(self.track) is True: try: ppil_image = Image.open(self.track) except: ppil_image = None self.tk_img = None self.track_image_obj = None return 'error', 'Not a recognised image format ' + self.track else: ppil_image = None self.tk_img = None self.track_image_obj = None return 'error', 'Track file not found ' + self.track tags, gps_tags = self.read_tags(ppil_image) # display track image if ppil_image is not None: try: #rotate the image # print self.image_width,self.image_height if self.image_rotate != 0: ppil_image = ppil_image.rotate(self.image_rotate, expand=True) self.image_width, self.image_height = ppil_image.size # print self.image_width,self.image_height datetime = dictread(tags, 'DateTimeOrigional', dictread(tags, 'DateTime', None)) description = dictread(tags, 'ImageDescription', None) # location = self.getLocation(ppil_image) # Auto-rotate the image if the EXIF data has orientation information. orientation = dictread(tags, 'Orientation', None) ppil_image = self.rotate_image(ppil_image, orientation) if self.command == 'original': # display image at its original size if self.has_coords is False: # load and display the unmodified image in centre self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( self.show_canvas_centre_x + self.show_canvas_x1, self.show_canvas_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) else: # load and display the unmodified image at x1,y1 self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( self.window_x1 + self.show_canvas_x1, self.window_y1 + self.show_canvas_y1, image=self.tk_img, anchor=NW) elif self.command in ('fit', 'shrink'): # shrink fit the window or screen preserving aspect if self.has_coords is True: window_width = self.window_x2 - self.window_x1 window_height = self.window_y2 - self.window_y1 window_centre_x = (self.window_x2 + self.window_x1) / 2 window_centre_y = (self.window_y2 + self.window_y1) / 2 else: window_width = self.show_canvas_width window_height = self.show_canvas_height window_centre_x = self.show_canvas_centre_x window_centre_y = self.show_canvas_centre_y if (self.image_width > window_width or self.image_height > window_height and self.command == 'fit') or (self.command == 'shrink'): # print 'show canvas',self.show_canvas_x1,self.show_canvas_y1,self.show_canvas_x2,self.show_canvas_y2 # print 'canvas width/height/centre',self.show_canvas_width,self.show_canvas_height,self.show_canvas_centre_x,self.show_canvas_centre_y # print 'window dimensions/centre',window_width,window_height,window_centre_x,window_centre_y # print # original image is larger or , shrink it to fit the screen preserving aspect # print ppil_image.size ppil_image.thumbnail( (int(window_width), int(window_height)), eval(self.image_filter)) # print ppil_image.size self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) else: # fitting and original image is smaller, expand it to fit the screen preserving aspect prop_x = float(window_width) / self.image_width prop_y = float(window_height) / self.image_height if prop_x > prop_y: prop = prop_y else: prop = prop_x increased_width = int(self.image_width * prop) increased_height = int(self.image_height * prop) # print 'result',prop, increased_width,increased_height ppil_image = ppil_image.resize( (int(increased_width), int(increased_height)), eval(self.image_filter)) self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) elif self.command in ('warp'): # resize to window or screen without preserving aspect if self.has_coords is True: window_width = self.window_x2 - self.window_x1 window_height = self.window_y2 - self.window_y1 window_centre_x = (self.window_x2 + self.window_x1) / 2 window_centre_y = (self.window_y2 + self.window_y1) / 2 else: window_width = self.show_canvas_width window_height = self.show_canvas_height window_centre_x = self.show_canvas_centre_x window_centre_y = self.show_canvas_centre_y # print 'window',window_width,window_height,window_centre_x,window_centre_y,self.show_canvas_x1,self.show_canvas_y1,'\n' ppil_image = ppil_image.resize( (int(window_width), int(window_height)), eval(self.image_filter)) self.tk_img = ImageTk.PhotoImage(ppil_image) del ppil_image self.track_image_obj = self.canvas.create_image( window_centre_x + self.show_canvas_x1, window_centre_y + self.show_canvas_y1, image=self.tk_img, anchor=CENTER) except IOError: self.tk_img = None self.track_image_obj = None return 'error', 'Error processing the file, probably truncation error: ' + self.track except Exception as ex: self.tk_img = None self.track_image_obj = None return 'error', 'Error processing the file: ' + str(ex).encode( 'utf-8') + ' --> ' + self.track self.canvas.itemconfig(self.track_image_obj, state='hidden') return 'normal', 'track content loaded' def show_track_content(self): self.canvas.itemconfig(self.track_image_obj, state='normal') def hide_track_content(self): if self.pause_text_obj is not None: self.canvas.delete(self.pause_text_obj) self.pause_text_obj = None # self.canvas.update_idletasks( ) self.canvas.itemconfig(self.track_image_obj, state='hidden') self.canvas.delete(self.track_image_obj) self.tk_img = None def parse_window(self, line): fields = line.split() # check there is a command field if len(fields) < 1: return 'error', 'No command field', '', False, 0, 0, 0, 0, '' # deal with original whch has 0 or 2 arguments image_filter = '' if fields[0] == 'original': if len(fields) not in (1, 3): return 'error', 'Original has wrong number of arguments', '', False, 0, 0, 0, 0, '' # deal with window coordinates if len(fields) == 3: # window is specified if not (fields[1].isdigit() and fields[2].isdigit()): return 'error', 'coordinates are not numbers', '', False, 0, 0, 0, 0, '' has_window = True return 'normal', '', fields[0], has_window, float( fields[1]), float(fields[2]), 0, 0, image_filter else: # no window has_window = False return 'normal', '', fields[ 0], has_window, 0, 0, 0, 0, image_filter # deal with remainder which has 1, 2, 5 or 6arguments # check basic syntax if fields[0] not in ('shrink', 'fit', 'warp'): return 'error', 'illegal command' + fields[ 0], '', False, 0, 0, 0, 0, '' if len(fields) not in (1, 2, 3, 5, 6): return 'error', 'wrong number of fields' + str( len(fields)), '', False, 0, 0, 0, 0, '' if len(fields) == 6 and fields[5] not in ('NEAREST', 'BILINEAR', 'BICUBIC', 'ANTIALIAS'): return 'error', 'wrong filter or params' + fields[ 5], '', False, 0, 0, 0, 0, '' if len(fields) == 2 and (fields[1] not in ('NEAREST', 'BILINEAR', 'BICUBIC', 'ANTIALIAS') and '*' not in fields[1]): return 'error', 'wrong filter or params' + fields[ 1], '', False, 0, 0, 0, 0, '' if len(fields) == 3 and fields[2] not in ('NEAREST', 'BILINEAR', 'BICUBIC', 'ANTIALIAS'): return 'error', 'wrong filter or params' + fields[ 2], '', False, 0, 0, 0, 0, '' # deal with no window coordinates and no if len(fields) == 1: has_window = False return 'normal', '', fields[ 0], has_window, 0, 0, 0, 0, 'Image.NEAREST' # deal with window coordinates in +* format with optional filter if len(fields) in (2, 3) and '*' in fields[1]: status, message, x1, y1, x2, y2 = parse_rectangle(fields[1]) if status == 'error': return 'error', message, '', False, 0, 0, 0, 0, '' else: has_window = True if len(fields) == 3: image_filter = 'Image.' + fields[2] else: image_filter = 'Image.NEAREST' return 'normal', '', fields[ 0], has_window, x1, y1, x2, y2, image_filter if len(fields) in (5, 6): # window is specified in x1 y1 x2 y2 if not (fields[1].isdigit() and fields[2].isdigit() and fields[3].isdigit() and fields[4].isdigit()): return 'error', 'coords are not numbers', '', False, 0, 0, 0, 0, '' has_window = True if len(fields) == 6: image_filter = 'Image.' + fields[5] else: image_filter = 'Image.NEAREST' return 'normal', '', fields[0], has_window, float( fields[1]), float(fields[2]), float(fields[3]), float( fields[4]), image_filter else: # no window has_window = False if len(fields) == 2: image_filter = 'Image.' + fields[1] else: image_filter = 'Image.NEAREST' return 'normal', '', fields[ 0], has_window, 0, 0, 0, 0, image_filter