def view(self, item, zoom=0, rotation=0): """ view an image """ logger.log( 9, 'view(item, zoom=%s, rotation=%s)', zoom, rotation) if self.blend: self.blend.stop() self.blend.remove() self.blend = None if zoom: self.event_context = 'image_zoom' else: self.event_context = 'image' filename = item.filename self.fileitem = item self.parent = item.menuw if not self.free_cache in item.menuw.show_callbacks: item.menuw.show_callbacks.append(self.free_cache) self.filename = filename self.rotation = rotation if filename and len(filename) > 0: image = self.osd.loadbitmap(filename, cache=self.bitmapcache) else: # Using Container-Image image, w, h = item.loadimage() if not self.__added_app: rc.add_app(self) self.__added_app = True if not image: self.osd.clearscreen(color=self.osd.COL_BLACK) self.osd.drawstringframed(_('Can\'t Open Image\n"%s"') % Unicode(filename), config.OSD_OVERSCAN_LEFT + 20, config.OSD_OVERSCAN_TOP + 20, self.osd.width - (config.OSD_OVERSCAN_LEFT+config.OSD_OVERSCAN_RIGHT) - 40, self.osd.height - (config.OSD_OVERSCAN_TOP+config.OSD_OVERSCAN_BOTTOM) - 40, self.osd.getfont(config.OSD_DEFAULT_FONTNAME, config.OSD_DEFAULT_FONTSIZE), fgcolor=self.osd.COL_ORANGE, align_h='center', align_v='center', mode='soft') self.osd.update() return width, height = image.get_size() # Bounding box default values bbx = bby = bbw = bbh = 0 if zoom: # Translate the 9-element grid to bounding boxes if config.IMAGEVIEWER_REVERSED_IMAGES: if self.rotation == 90: bb = { 1:(2,2), 2:(2,1), 3:(2,0), 4:(1,2), 5:(1,1), 6:(1,0), 7:(0,2), 8:(0,1), 9:(0,0) } elif self.rotation == 180: bb = { 1:(2,0), 2:(1,0), 3:(0,0), 4:(2,1), 5:(1,1), 6:(0,1), 7:(2,2), 8:(1,2), 9:(0,2) } elif self.rotation == 270: bb = { 1:(0,0), 2:(0,1), 3:(0,2), 4:(1,0), 5:(1,1), 6:(1,2), 7:(2,0), 8:(2,1), 9:(2,2) } else: bb = { 1:(0,2), 2:(1,2), 3:(2,2), 4:(0,1), 5:(1,1), 6:(2,1), 7:(0,0), 8:(1,0), 9:(2,0) } else: if self.rotation == 90: bb = { 1:(2,0), 2:(2,1), 3:(2,2), 4:(1,0), 5:(1,1), 6:(1,2), 7:(0,0), 8:(0,1), 9:(0,2) } elif self.rotation == 180: bb = { 1:(2,2), 2:(1,2), 3:(0,2), 4:(2,1), 5:(1,1), 6:(0,1), 7:(2,0), 8:(1,0), 9:(0,0) } elif self.rotation == 270: bb = { 1:(0,2), 2:(0,1), 3:(0,0), 4:(1,2), 5:(1,1), 6:(1,0), 7:(2,2), 8:(2,1), 9:(2,0) } else: bb = { 1:(0,0), 2:(1,0), 3:(2,0), 4:(0,1), 5:(1,1), 6:(2,1), 7:(0,2), 8:(1,2), 9:(2,2) } if isinstance(zoom, int): h, v = bb[zoom] else: h, v = bb[zoom[0]] # Bounding box center bbcx = ([1, 3, 5][h]) * width / 6 bbcy = ([1, 3, 5][v]) * height / 6 if self.rotation % 180: # different calculations because image width is screen height scale_x = float(self.osd_width) / (height / 3) scale_y = float(self.osd_height) / (width / 3) scale = min(scale_x, scale_y) # read comment for the bbw and bbh calculations below bbw = min(max((width / 3) * scale, self.osd_height), width) / scale bbh = min(max((height / 3) * scale, self.osd_width), height) / scale else: scale_x = float(self.osd_width) / (width / 3) scale_y = float(self.osd_height) / (height / 3) scale = min(scale_x, scale_y) # the bb width is the width / 3 * scale, to avoid black bars left # and right exapand it to the osd_width but not if this is more than the # image width (same for height) bbw = min(max((width / 3) * scale, self.osd_width), width) / scale bbh = min(max((height / 3) * scale, self.osd_height), height) / scale # calculate the beginning of the bounding box bbx = max(0, bbcx - bbw/2) bby = max(0, bbcy - bbh/2) if bbx + bbw > width: bbx = width - bbw if bby + bbh > height: bby = height - bbh if self.rotation % 180: new_h, new_w = bbw * scale, bbh * scale else: new_w, new_h = bbw * scale, bbh * scale else: if self.rotation % 180: height, width = width, height # scale_x = scale_y = 1.0 # if width > osd_width: scale_x = float(osd_width) / width # if height > osd_height: scale_y = float(osd_height) / height scale_x = float(self.osd_width) / width scale_y = float(self.osd_height) / height scale = min(scale_x, scale_y) new_w, new_h = int(scale*width), int(scale*height) # Now we have all necessary information about zoom yes/no and # the kind of rotation x = (self.osd_width - new_w) / 2 y = (self.osd_height - new_h) / 2 last_item,last_image = self.last_image if not isinstance(zoom, int): # change zoom based on rotation if self.rotation == 90: zoom = zoom[0], -zoom[2], zoom[1] if self.rotation == 180: zoom = zoom[0], -zoom[1], -zoom[2] if self.rotation == 270: zoom = zoom[0], zoom[2], -zoom[1] # don't move outside the image if bbx + zoom[1] < 0: zoom = zoom[0], -bbx, zoom[2] if bbx + zoom[1] > width - bbw: zoom = zoom[0], width - (bbw + bbx), zoom[2] if bby + zoom[2] < 0: zoom = zoom[0], zoom[1], -bby if bby + zoom[2] > height - bbh: zoom = zoom[0], zoom[1], height - (bbh + bby) # change bbx bbx += zoom[1] bby += zoom[2] # save zoom, but revert the rotation mix up if not isinstance(zoom, int) and self.rotation: if self.rotation == 90: zoom = zoom[0], zoom[2], -zoom[1] if self.rotation == 180: zoom = zoom[0], -zoom[1], -zoom[2] if self.rotation == 270: zoom = zoom[0], -zoom[2], zoom[1] self.zoom = zoom self.last_image = (item, (image, x, y, scale, bbx, bby, bbw, bbh, self.rotation)) if (last_image and last_item != item and config.IMAGEVIEWER_BLEND_MODE != None): screen = self.osd.screen.convert() screen.fill((0,0,0,0)) screen.blit(self.osd.zoomsurface(image, scale, bbx, bby, bbw, bbh, rotation=self.rotation).convert(), (x, y)) # update the OSD self.drawosd(layer=screen) self.blend = Transition(self.osd.screen, screen, config.IMAGEVIEWER_BLEND_MODE) self.blend.start() self.blend.inprogress.connect(self.__blend_done, item) else: self.osd.clearscreen(color=self.osd.COL_BLACK) self.osd.drawsurface(image, x, y, scale, bbx, bby, bbw, bbh, rotation=self.rotation) # update the OSD self.drawosd() self.__drawn(item)
class ImageViewer(GUIObject): def __init__(self): logger.log( 9, 'ImageViewer.__init__()') GUIObject.__init__(self) self.osd_mode = 0 # Draw file info on the image self.zoom = 0 # Image zoom self.zoom_btns = { str(IMAGE_NO_ZOOM):0, str(IMAGE_ZOOM_GRID1):1, str(IMAGE_ZOOM_GRID2):2, str(IMAGE_ZOOM_GRID3):3, str(IMAGE_ZOOM_GRID4):4, str(IMAGE_ZOOM_GRID5):5, str(IMAGE_ZOOM_GRID6):6, str(IMAGE_ZOOM_GRID7):7, str(IMAGE_ZOOM_GRID8):8, str(IMAGE_ZOOM_GRID9):9 } self.slideshow = config.IMAGEVIEWER_AUTOPLAY self.duration = config.IMAGEVIEWER_DURATION self.event_context = 'image' self.last_image = (None, None) self.render = render.get_singleton() self.osd = osd.get_singleton() self.osd_height = self.osd.height self.osd_width = self.osd.width * float(config.OSD_PIXEL_ASPECT) self.timer = None self.blend = None self.__added_app = False self.free_cache() def free_cache(self): """ free the current cache to save memory """ logger.log( 9, 'free_cache()') self.bitmapcache = util.objectcache.ObjectCache(3, desc='viewer') if self.parent and self.free_cache in self.parent.show_callbacks: self.parent.show_callbacks.remove(self.free_cache) def view(self, item, zoom=0, rotation=0): """ view an image """ logger.log( 9, 'view(item, zoom=%s, rotation=%s)', zoom, rotation) if self.blend: self.blend.stop() self.blend.remove() self.blend = None if zoom: self.event_context = 'image_zoom' else: self.event_context = 'image' filename = item.filename self.fileitem = item self.parent = item.menuw if not self.free_cache in item.menuw.show_callbacks: item.menuw.show_callbacks.append(self.free_cache) self.filename = filename self.rotation = rotation if filename and len(filename) > 0: image = self.osd.loadbitmap(filename, cache=self.bitmapcache) else: # Using Container-Image image, w, h = item.loadimage() if not self.__added_app: rc.add_app(self) self.__added_app = True if not image: self.osd.clearscreen(color=self.osd.COL_BLACK) self.osd.drawstringframed(_('Can\'t Open Image\n"%s"') % Unicode(filename), config.OSD_OVERSCAN_LEFT + 20, config.OSD_OVERSCAN_TOP + 20, self.osd.width - (config.OSD_OVERSCAN_LEFT+config.OSD_OVERSCAN_RIGHT) - 40, self.osd.height - (config.OSD_OVERSCAN_TOP+config.OSD_OVERSCAN_BOTTOM) - 40, self.osd.getfont(config.OSD_DEFAULT_FONTNAME, config.OSD_DEFAULT_FONTSIZE), fgcolor=self.osd.COL_ORANGE, align_h='center', align_v='center', mode='soft') self.osd.update() return width, height = image.get_size() # Bounding box default values bbx = bby = bbw = bbh = 0 if zoom: # Translate the 9-element grid to bounding boxes if config.IMAGEVIEWER_REVERSED_IMAGES: if self.rotation == 90: bb = { 1:(2,2), 2:(2,1), 3:(2,0), 4:(1,2), 5:(1,1), 6:(1,0), 7:(0,2), 8:(0,1), 9:(0,0) } elif self.rotation == 180: bb = { 1:(2,0), 2:(1,0), 3:(0,0), 4:(2,1), 5:(1,1), 6:(0,1), 7:(2,2), 8:(1,2), 9:(0,2) } elif self.rotation == 270: bb = { 1:(0,0), 2:(0,1), 3:(0,2), 4:(1,0), 5:(1,1), 6:(1,2), 7:(2,0), 8:(2,1), 9:(2,2) } else: bb = { 1:(0,2), 2:(1,2), 3:(2,2), 4:(0,1), 5:(1,1), 6:(2,1), 7:(0,0), 8:(1,0), 9:(2,0) } else: if self.rotation == 90: bb = { 1:(2,0), 2:(2,1), 3:(2,2), 4:(1,0), 5:(1,1), 6:(1,2), 7:(0,0), 8:(0,1), 9:(0,2) } elif self.rotation == 180: bb = { 1:(2,2), 2:(1,2), 3:(0,2), 4:(2,1), 5:(1,1), 6:(0,1), 7:(2,0), 8:(1,0), 9:(0,0) } elif self.rotation == 270: bb = { 1:(0,2), 2:(0,1), 3:(0,0), 4:(1,2), 5:(1,1), 6:(1,0), 7:(2,2), 8:(2,1), 9:(2,0) } else: bb = { 1:(0,0), 2:(1,0), 3:(2,0), 4:(0,1), 5:(1,1), 6:(2,1), 7:(0,2), 8:(1,2), 9:(2,2) } if isinstance(zoom, int): h, v = bb[zoom] else: h, v = bb[zoom[0]] # Bounding box center bbcx = ([1, 3, 5][h]) * width / 6 bbcy = ([1, 3, 5][v]) * height / 6 if self.rotation % 180: # different calculations because image width is screen height scale_x = float(self.osd_width) / (height / 3) scale_y = float(self.osd_height) / (width / 3) scale = min(scale_x, scale_y) # read comment for the bbw and bbh calculations below bbw = min(max((width / 3) * scale, self.osd_height), width) / scale bbh = min(max((height / 3) * scale, self.osd_width), height) / scale else: scale_x = float(self.osd_width) / (width / 3) scale_y = float(self.osd_height) / (height / 3) scale = min(scale_x, scale_y) # the bb width is the width / 3 * scale, to avoid black bars left # and right exapand it to the osd_width but not if this is more than the # image width (same for height) bbw = min(max((width / 3) * scale, self.osd_width), width) / scale bbh = min(max((height / 3) * scale, self.osd_height), height) / scale # calculate the beginning of the bounding box bbx = max(0, bbcx - bbw/2) bby = max(0, bbcy - bbh/2) if bbx + bbw > width: bbx = width - bbw if bby + bbh > height: bby = height - bbh if self.rotation % 180: new_h, new_w = bbw * scale, bbh * scale else: new_w, new_h = bbw * scale, bbh * scale else: if self.rotation % 180: height, width = width, height # scale_x = scale_y = 1.0 # if width > osd_width: scale_x = float(osd_width) / width # if height > osd_height: scale_y = float(osd_height) / height scale_x = float(self.osd_width) / width scale_y = float(self.osd_height) / height scale = min(scale_x, scale_y) new_w, new_h = int(scale*width), int(scale*height) # Now we have all necessary information about zoom yes/no and # the kind of rotation x = (self.osd_width - new_w) / 2 y = (self.osd_height - new_h) / 2 last_item,last_image = self.last_image if not isinstance(zoom, int): # change zoom based on rotation if self.rotation == 90: zoom = zoom[0], -zoom[2], zoom[1] if self.rotation == 180: zoom = zoom[0], -zoom[1], -zoom[2] if self.rotation == 270: zoom = zoom[0], zoom[2], -zoom[1] # don't move outside the image if bbx + zoom[1] < 0: zoom = zoom[0], -bbx, zoom[2] if bbx + zoom[1] > width - bbw: zoom = zoom[0], width - (bbw + bbx), zoom[2] if bby + zoom[2] < 0: zoom = zoom[0], zoom[1], -bby if bby + zoom[2] > height - bbh: zoom = zoom[0], zoom[1], height - (bbh + bby) # change bbx bbx += zoom[1] bby += zoom[2] # save zoom, but revert the rotation mix up if not isinstance(zoom, int) and self.rotation: if self.rotation == 90: zoom = zoom[0], zoom[2], -zoom[1] if self.rotation == 180: zoom = zoom[0], -zoom[1], -zoom[2] if self.rotation == 270: zoom = zoom[0], -zoom[2], zoom[1] self.zoom = zoom self.last_image = (item, (image, x, y, scale, bbx, bby, bbw, bbh, self.rotation)) if (last_image and last_item != item and config.IMAGEVIEWER_BLEND_MODE != None): screen = self.osd.screen.convert() screen.fill((0,0,0,0)) screen.blit(self.osd.zoomsurface(image, scale, bbx, bby, bbw, bbh, rotation=self.rotation).convert(), (x, y)) # update the OSD self.drawosd(layer=screen) self.blend = Transition(self.osd.screen, screen, config.IMAGEVIEWER_BLEND_MODE) self.blend.start() self.blend.inprogress.connect(self.__blend_done, item) else: self.osd.clearscreen(color=self.osd.COL_BLACK) self.osd.drawsurface(image, x, y, scale, bbx, bby, bbw, bbh, rotation=self.rotation) # update the OSD self.drawosd() self.__drawn(item) def __drawn(self, item): if plugin.getbyname('osd'): plugin.getbyname('osd').draw(('osd', None), self.osd) # draw self.osd.update() # start timer if self.duration and self.slideshow and not self.timer: self.timer = kaa.OneShotTimer(self.signalhandler) self.timer.start(self.duration) # stop slideshow at the end if configured try: index = item.parent.play_items.index(item)+1 length = len(item.parent.play_items) if index == length: self.slideshow = config.IMAGEVIEWER_AUTOPLAY # send information event to LCD2 rc.post_event(Event('IMAGE_VIEW_INFO', arg=(index, length, item.name))) except Exception, why: logger.warning('Invalid parent item: %s', why) # XXX Hack to move the selected item to the current showing image # XXX TODO: find a way to add it to directory.py or playlist.py if item.parent and hasattr(item.parent, 'menu') and item.parent.menu and \ item in item.parent.menu.choices: item.parent.menu.selected = item item.menuw.force_page_rebuild = True return None
def view(self, item, zoom=0, rotation=0): #print 'view(self, item, zoom=%s, rotation=%s)' % (zoom, rotation) if zoom: self.app_mode = 'image_zoom' else: self.app_mode = 'image' filename = item.filename self.fileitem = item self.parent = item.menuw if not self.free_cache in item.menuw.show_callbacks: item.menuw.show_callbacks.append(self.free_cache) self.filename = filename self.rotation = rotation if filename and len(filename) > 0: image = self.osd.loadbitmap(filename, cache=self.bitmapcache) else: # Using Container-Image image = item.loadimage() rc.app(self) if not image: self.osd.clearscreen(color=self.osd.COL_BLACK) self.osd.drawstringframed( _('Can\'t Open Image\n\'%s\'') % Unicode(filename), config.OSD_OVERSCAN_X + 20, config.OSD_OVERSCAN_Y + 20, self.osd.width - 2 * config.OSD_OVERSCAN_X - 40, self.osd.height - 2 * config.OSD_OVERSCAN_Y - 40, self.osd.getfont(config.OSD_DEFAULT_FONTNAME, config.OSD_DEFAULT_FONTSIZE), fgcolor=self.osd.COL_ORANGE, align_h='center', align_v='center', mode='soft') self.osd.update() return width, height = image.get_size() # Bounding box default values bbx = bby = bbw = bbh = 0 if zoom: # Translate the 9-element grid to bounding boxes if self.rotation == 90: bb = { 1: (2, 0), 2: (2, 1), 3: (2, 2), 4: (1, 0), 5: (1, 1), 6: (1, 2), 7: (0, 0), 8: (0, 1), 9: (0, 2) } elif self.rotation == 180: bb = { 1: (2, 2), 2: (1, 2), 3: (0, 2), 4: (2, 1), 5: (1, 1), 6: (0, 1), 7: (2, 0), 8: (1, 0), 9: (0, 0) } elif self.rotation == 270: bb = { 1: (0, 2), 2: (0, 1), 3: (0, 0), 4: (1, 2), 5: (1, 1), 6: (1, 0), 7: (2, 2), 8: (2, 1), 9: (2, 0) } else: bb = { 1: (0, 0), 2: (1, 0), 3: (2, 0), 4: (0, 1), 5: (1, 1), 6: (2, 1), 7: (0, 2), 8: (1, 2), 9: (2, 2) } if isinstance(zoom, int): h, v = bb[zoom] else: h, v = bb[zoom[0]] # Bounding box center bbcx = ([1, 3, 5][h]) * width / 6 bbcy = ([1, 3, 5][v]) * height / 6 if self.rotation % 180: # different calculations because image width is screen height scale_x = float(self.osd.width) / (height / 3) scale_y = float(self.osd.height) / (width / 3) scale = min(scale_x, scale_y) # read comment for the bbw and bbh calculations below bbw = min(max( (width / 3) * scale, self.osd.height), width) / scale bbh = min(max( (height / 3) * scale, self.osd.width), height) / scale else: scale_x = float(self.osd.width) / (width / 3) scale_y = float(self.osd.height) / (height / 3) scale = min(scale_x, scale_y) # the bb width is the width / 3 * scale, to avoid black bars left # and right exapand it to the osd.width but not if this is more than the # image width (same for height) bbw = min(max( (width / 3) * scale, self.osd.width), width) / scale bbh = min(max( (height / 3) * scale, self.osd.height), height) / scale # calculate the beginning of the bounding box bbx = max(0, bbcx - bbw / 2) bby = max(0, bbcy - bbh / 2) if bbx + bbw > width: bbx = width - bbw if bby + bbh > height: bby = height - bbh if self.rotation % 180: new_h, new_w = bbw * scale, bbh * scale else: new_w, new_h = bbw * scale, bbh * scale else: if self.rotation % 180: height, width = width, height # scale_x = scale_y = 1.0 # if width > osd.width: scale_x = float(osd.width) / width # if height > osd.height: scale_y = float(osd.height) / height scale_x = float(self.osd.width) / width scale_y = float(self.osd.height) / height scale = min(scale_x, scale_y) new_w, new_h = int(scale * width), int(scale * height) # Now we have all necessary informations about zoom yes/no and # the kind of rotation x = (self.osd.width - new_w) / 2 y = (self.osd.height - new_h) / 2 last_image = self.last_image[1] if not isinstance(zoom, int): # change zoom based on rotation if self.rotation == 90: zoom = zoom[0], -zoom[2], zoom[1] if self.rotation == 180: zoom = zoom[0], -zoom[1], -zoom[2] if self.rotation == 270: zoom = zoom[0], zoom[2], -zoom[1] # don't move outside the image if bbx + zoom[1] < 0: zoom = zoom[0], -bbx, zoom[2] if bbx + zoom[1] > width - bbw: zoom = zoom[0], width - (bbw + bbx), zoom[2] if bby + zoom[2] < 0: zoom = zoom[0], zoom[1], -bby if bby + zoom[2] > height - bbh: zoom = zoom[0], zoom[1], height - (bbh + bby) # change bbx bbx += zoom[1] bby += zoom[2] if (last_image and self.last_image[0] != item and config.IMAGEVIEWER_BLEND_MODE != None): screen = self.osd.screen.convert() screen.fill((0, 0, 0, 0)) screen.blit( self.osd.zoomsurface(image, scale, bbx, bby, bbw, bbh, rotation=self.rotation).convert(), (x, y)) # update the OSD self.drawosd(layer=screen) blend = Transition(self.osd.screen, screen, config.IMAGEVIEWER_BLEND_MODE) blend.start() while not blend.finished: rc.poll() blend.remove() else: self.osd.clearscreen(color=self.osd.COL_BLACK) self.osd.drawsurface(image, x, y, scale, bbx, bby, bbw, bbh, rotation=self.rotation) # update the OSD self.drawosd() if plugin.getbyname('osd'): plugin.getbyname('osd').draw(('osd', None), self.osd) # draw self.osd.update() # start timer if self.fileitem.duration and self.slideshow and not self.signal_registered: rc.register(self.signalhandler, False, self.fileitem.duration * 100) self.signal_registered = True self.last_image = (item, (image, x, y, scale, bbx, bby, bbw, bbh, self.rotation)) # XXX Hack to move the selected item to the current showing image # XXX TODO: find a way to add it to directory.py or playlist.py if item.parent and hasattr(item.parent, 'menu') and item.parent.menu and \ item in item.parent.menu.choices: item.parent.menu.selected = item item.menuw.force_page_rebuild = True # save zoom, but revert the rotation mix up if not isinstance(zoom, int) and self.rotation: if self.rotation == 90: zoom = zoom[0], zoom[2], -zoom[1] if self.rotation == 180: zoom = zoom[0], -zoom[1], -zoom[2] if self.rotation == 270: zoom = zoom[0], -zoom[2], zoom[1] self.zoom = zoom return None