def get_thumbnail(self, page=None, width=128, height=128, create=False): """Return a thumbnail pixbuf of <page> that fit in a box with dimensions <width>x<height>. Return a thumbnail for the current page if <page> is None. If <create> is True, and <width>x<height> <= 128x128, the thumbnail is also stored on disk. """ self._wait_on_page(page) path = self.get_path_to_page(page) if width <= 128 and height <= 128: thumb = thumbnail.get_thumbnail(path, create) else: try: if "gif" not in path[-3:].lower(): thumb = gtk.gdk.pixbuf_new_from_file_at_size(path, width, height) else: thumb = gtk.gdk.PixbufAnimation(path).get_static_image() src_width = thumb.get_width() src_height = thumb.get_height() if float(src_width) / width > float(src_height) / height: thumb = thumb.scale_simple(width, int(max(src_height * width / src_width, 1)), gtk.gdk.INTERP_TILES) else: thumb = thumb.scale_simple(int(max(src_width * height / src_height, 1)), height, gtk.gdk.INTERP_TILES) except Exception: thumb = None if thumb is None: thumb = self._get_missing_image() thumb = image.fit_in_rectangle(thumb, width, height) return thumb
def add_extra_image(self, path): """Add an imported image (at <path>) to the end of the image list.""" thumb = thumbnail.get_thumbnail(path, create=False) if thumb is None: thumb = self.render_icon(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_DIALOG) thumb = image.fit_in_rectangle(thumb, 67, 100) thumb = image.add_border(thumb, 1, 0x555555FF) self._liststore.append([thumb, os.path.basename(path), path])
def _add_book(self, book): """Add the <book> to the ListStore (and thus to the _BookArea).""" pixbuf = self._library.backend.get_book_cover(book) if pixbuf is None: pixbuf = self._library.render_icon(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_DIALOG) # The ratio (0.67) is just above the normal aspect ratio for books. pixbuf = image.fit_in_rectangle( pixbuf, int(0.67 * prefs['library cover size']), prefs['library cover size']) pixbuf = image.add_border(pixbuf, 1, 0xFFFFFFFF) self._liststore.append([pixbuf, book])
def _add_book(self, book): """Add the <book> to the ListStore (and thus to the _BookArea).""" pixbuf = self._library.backend.get_book_cover(book) if pixbuf is None: pixbuf = self._library.render_icon(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_DIALOG) # The ratio (0.67) is just above the normal aspect ratio for books. pixbuf = image.fit_in_rectangle(pixbuf, int(0.67 * prefs['library cover size']), prefs['library cover size']) pixbuf = image.add_border(pixbuf, 1, 0xFFFFFFFF) self._liststore.append([pixbuf, book])
def _draw_image(self, at_bottom, scroll): def pixb_process(pixbuf): """ Small helper for common stuff to few pixbufs. """ if prefs['horizontal flip']: pixbuf = pixbuf.flip(horizontal=True) if prefs['vertical flip']: pixbuf = pixbuf.flip(horizontal=False) pixbuf = self.enhancer.enhance(pixbuf) return pixbuf self._waiting_for_redraw = False self._display_active_widgets() if not self.file_handler.file_loaded: return False area_width, area_height = self.get_visible_area_size() if self.zoom_mode == preferences.ZOOM_MODE_HEIGHT: scaled_width = -1 else: scaled_width = area_width if self.zoom_mode == preferences.ZOOM_MODE_WIDTH: scaled_height = -1 else: scaled_height = area_height scale_up = prefs['stretch'] self.is_virtual_double_page = \ self.file_handler.get_virtual_double_page() # TODO: If and when it becomes possible to resize (and do other things) # to PixbufAnimation objects, change these hacks to make them work # correctly. All the conditionals about animated are part of this if self.displayed_double(): left_pixbuf, right_pixbuf = self.file_handler.get_pixbufs() if self.is_manga_mode: right_pixbuf, left_pixbuf = left_pixbuf, right_pixbuf # instead of modifying returns, just do two extra calls here left_animated = isinstance(left_pixbuf, gtk.gdk.PixbufAnimation) right_animated = isinstance(right_pixbuf, gtk.gdk.PixbufAnimation) left_unscaled_x = left_pixbuf.get_width() left_unscaled_y = left_pixbuf.get_height() right_unscaled_x = right_pixbuf.get_width() right_unscaled_y = right_pixbuf.get_height() left_rotation = prefs['rotation'] right_rotation = prefs['rotation'] if prefs['auto rotate from exif']: if not left_animated: left_rotation += image.get_implied_rotation(left_pixbuf) left_rotation = left_rotation % 360 if not right_animated: right_rotation += image.get_implied_rotation(right_pixbuf) right_rotation = right_rotation % 360 if self.zoom_mode == preferences.ZOOM_MODE_MANUAL: if not left_animated and left_rotation in (90, 270): total_width = left_unscaled_y total_height = left_unscaled_x else: total_width = left_unscaled_x total_height = left_unscaled_y if not right_animated and right_rotation in (90, 270): total_width += right_unscaled_y total_height += right_unscaled_x else: total_width += right_unscaled_x total_height += right_unscaled_y total_width += 2 # For the 2 px gap between images. scaled_width = int(self._manual_zoom * total_width / 100) scaled_height = int(self._manual_zoom * total_height / 100) scale_up = True left_pixbuf, right_pixbuf = image.fit_2_in_rectangle( left_pixbuf, right_pixbuf, scaled_width, scaled_height, scale_up=scale_up, rotation1=left_rotation, rotation2=right_rotation, animated1=left_animated, animated2=right_animated) if not left_animated: pixb_process(left_pixbuf) self.left_image.set_from_pixbuf(left_pixbuf) else: self.left_image.set_from_animation(left_pixbuf) if not right_animated: pixb_process(right_pixbuf) self.right_image.set_from_pixbuf(right_pixbuf) else: self.right_image.set_from_animation(right_pixbuf) x_padding = (area_width - left_pixbuf.get_width() - right_pixbuf.get_width()) / 2 y_padding = (area_height - max(left_pixbuf.get_height(), right_pixbuf.get_height())) / 2 if not left_animated and left_rotation in (90, 270): left_scale_percent = (100.0 * left_pixbuf.get_width() / left_unscaled_y) else: left_scale_percent = (100.0 * left_pixbuf.get_width() / left_unscaled_x) if not right_animated and right_rotation in (90, 270): right_scale_percent = (100.0 * right_pixbuf.get_width() / right_unscaled_y) else: right_scale_percent = (100.0 * right_pixbuf.get_width() / right_unscaled_x) self.statusbar.set_page_number( self.file_handler.get_current_page(), self.file_handler.get_number_of_pages(), double_page=True) self.statusbar.set_resolution( (left_unscaled_x, left_unscaled_y, left_scale_percent), (right_unscaled_x, right_unscaled_y, right_scale_percent)) if prefs['smart bg']: bg_colour = image.get_most_common_edge_colour(left_pixbuf) self.set_bg_colour(bg_colour) left_filename, right_filename = \ self.file_handler.get_page_filename(double=True) if self.is_manga_mode: left_filename, right_filename = right_filename, left_filename self.statusbar.set_filename(left_filename + ', ' + right_filename) else: pixbuf = self.file_handler.get_pixbufs(single=True) # instead of modifying returns, just do an extra single call here animated = isinstance(pixbuf, gtk.gdk.PixbufAnimation) unscaled_x = pixbuf.get_width() unscaled_y = pixbuf.get_height() rotation = prefs['rotation'] if not animated and prefs['auto rotate from exif']: rotation += image.get_implied_rotation(pixbuf) rotation = rotation % 360 if self.zoom_mode == preferences.ZOOM_MODE_MANUAL: if not animated: scaled_width = int(self._manual_zoom * unscaled_x / 100) scaled_height = int(self._manual_zoom * unscaled_y / 100) if rotation in (90, 270): scaled_width, scaled_height = scaled_height, scaled_width scale_up = True pixbuf = image.fit_in_rectangle(pixbuf, scaled_width, scaled_height, scale_up=scale_up, rotation=rotation, animated=animated) if not animated: pixbuf = pixb_process(pixbuf) self.left_image.set_from_pixbuf(pixbuf) else: self.left_image.set_from_animation(pixbuf) self.right_image.clear() x_padding = (area_width - pixbuf.get_width()) / 2 y_padding = (area_height - pixbuf.get_height()) / 2 if not animated and rotation in (90, 270): scale_percent = 100.0 * pixbuf.get_width() / unscaled_y else: scale_percent = 100.0 * pixbuf.get_width() / unscaled_x self.statusbar.set_page_number( self.file_handler.get_current_page(), self.file_handler.get_number_of_pages()) self.statusbar.set_resolution( (unscaled_x, unscaled_y, scale_percent)) self.statusbar.set_filename(self.file_handler.get_page_filename()) if prefs['smart bg']: bg_colour = image.get_most_common_edge_colour(pixbuf) self.set_bg_colour(bg_colour) self._image_box.window.freeze_updates() self._main_layout.move(self._image_box, max(0, x_padding), max(0, y_padding)) self.left_image.show() if self.displayed_double(): self.right_image.show() else: self.right_image.hide() self._main_layout.set_size(*self._image_box.size_request()) if scroll: if at_bottom: self.scroll_to_fixed(horiz='endsecond', vert='bottom') else: self.scroll_to_fixed(horiz='startfirst', vert='top') self._image_box.window.thaw_updates() self.statusbar.set_root(self.file_handler.get_base_filename()) self.statusbar.update() self.update_title() while gtk.events_pending(): gtk.main_iteration(False) enhance.draw_histogram(self.left_image) self.file_handler.do_cacheing() self.thumbnailsidebar.load_thumbnails() return False
def _draw_image(self, at_bottom, scroll): def pixb_process(pixbuf): """ Small helper for common stuff to few pixbufs. """ if prefs['horizontal flip']: pixbuf = pixbuf.flip(horizontal=True) if prefs['vertical flip']: pixbuf = pixbuf.flip(horizontal=False) pixbuf = self.enhancer.enhance(pixbuf) return pixbuf self._waiting_for_redraw = False self._display_active_widgets() if not self.file_handler.file_loaded: return False area_width, area_height = self.get_visible_area_size() if self.zoom_mode == preferences.ZOOM_MODE_HEIGHT: scaled_width = -1 else: scaled_width = area_width if self.zoom_mode == preferences.ZOOM_MODE_WIDTH: scaled_height = -1 else: scaled_height = area_height scale_up = prefs['stretch'] self.is_virtual_double_page = \ self.file_handler.get_virtual_double_page() # TODO: If and when it becomes possible to resize (and do other things) # to PixbufAnimation objects, change these hacks to make them work # correctly. All the conditionals about animated are part of this if self.displayed_double(): left_pixbuf, right_pixbuf = self.file_handler.get_pixbufs() if self.is_manga_mode: right_pixbuf, left_pixbuf = left_pixbuf, right_pixbuf # instead of modifying returns, just do two extra calls here left_animated = isinstance(left_pixbuf, gtk.gdk.PixbufAnimation) right_animated = isinstance(right_pixbuf, gtk.gdk.PixbufAnimation) left_unscaled_x = left_pixbuf.get_width() left_unscaled_y = left_pixbuf.get_height() right_unscaled_x = right_pixbuf.get_width() right_unscaled_y = right_pixbuf.get_height() left_rotation = prefs['rotation'] right_rotation = prefs['rotation'] if prefs['auto rotate from exif']: if not left_animated: left_rotation += image.get_implied_rotation(left_pixbuf) left_rotation = left_rotation % 360 if not right_animated: right_rotation += image.get_implied_rotation(right_pixbuf) right_rotation = right_rotation % 360 if self.zoom_mode == preferences.ZOOM_MODE_MANUAL: if not left_animated and left_rotation in (90, 270): total_width = left_unscaled_y total_height = left_unscaled_x else: total_width = left_unscaled_x total_height = left_unscaled_y if not right_animated and right_rotation in (90, 270): total_width += right_unscaled_y total_height += right_unscaled_x else: total_width += right_unscaled_x total_height += right_unscaled_y total_width += 2 # For the 2 px gap between images. scaled_width = int(self._manual_zoom * total_width / 100) scaled_height = int(self._manual_zoom * total_height / 100) scale_up = True left_pixbuf, right_pixbuf = image.fit_2_in_rectangle( left_pixbuf, right_pixbuf, scaled_width, scaled_height, scale_up=scale_up, rotation1=left_rotation, rotation2=right_rotation, animated1=left_animated, animated2=right_animated) if not left_animated: pixb_process(left_pixbuf) self.left_image.set_from_pixbuf(left_pixbuf) else: self.left_image.set_from_animation(left_pixbuf) if not right_animated: pixb_process(right_pixbuf) self.right_image.set_from_pixbuf(right_pixbuf) else: self.right_image.set_from_animation(right_pixbuf) x_padding = (area_width - left_pixbuf.get_width() - right_pixbuf.get_width()) / 2 y_padding = (area_height - max(left_pixbuf.get_height(), right_pixbuf.get_height())) / 2 if not left_animated and left_rotation in (90, 270): left_scale_percent = (100.0 * left_pixbuf.get_width() / left_unscaled_y) else: left_scale_percent = (100.0 * left_pixbuf.get_width() / left_unscaled_x) if not right_animated and right_rotation in (90, 270): right_scale_percent = (100.0 * right_pixbuf.get_width() / right_unscaled_y) else: right_scale_percent = (100.0 * right_pixbuf.get_width() / right_unscaled_x) self.statusbar.set_page_number( self.file_handler.get_current_page(), self.file_handler.get_number_of_pages(), double_page=True) self.statusbar.set_resolution( (left_unscaled_x, left_unscaled_y, left_scale_percent), (right_unscaled_x, right_unscaled_y, right_scale_percent)) if prefs['smart bg']: bg_colour = image.get_most_common_edge_colour(left_pixbuf) self.set_bg_colour(bg_colour) left_filename, right_filename = \ self.file_handler.get_page_filename(double=True) if self.is_manga_mode: left_filename, right_filename = right_filename, left_filename self.statusbar.set_filename(left_filename + ', ' + right_filename) else: pixbuf = self.file_handler.get_pixbufs(single=True) # instead of modifying returns, just do an extra single call here animated = isinstance(pixbuf, gtk.gdk.PixbufAnimation) unscaled_x = pixbuf.get_width() unscaled_y = pixbuf.get_height() rotation = prefs['rotation'] if not animated and prefs['auto rotate from exif']: rotation += image.get_implied_rotation(pixbuf) rotation = rotation % 360 if self.zoom_mode == preferences.ZOOM_MODE_MANUAL: if not animated: scaled_width = int(self._manual_zoom * unscaled_x / 100) scaled_height = int(self._manual_zoom * unscaled_y / 100) if rotation in (90, 270): scaled_width, scaled_height = scaled_height, scaled_width scale_up = True pixbuf = image.fit_in_rectangle(pixbuf, scaled_width, scaled_height, scale_up=scale_up, rotation=rotation, animated=animated) if not animated: pixbuf = pixb_process(pixbuf) self.left_image.set_from_pixbuf(pixbuf) else: self.left_image.set_from_animation(pixbuf) self.right_image.clear() x_padding = (area_width - pixbuf.get_width()) / 2 y_padding = (area_height - pixbuf.get_height()) / 2 if not animated and rotation in (90, 270): scale_percent = 100.0 * pixbuf.get_width() / unscaled_y else: scale_percent = 100.0 * pixbuf.get_width() / unscaled_x self.statusbar.set_page_number( self.file_handler.get_current_page(), self.file_handler.get_number_of_pages()) self.statusbar.set_resolution((unscaled_x, unscaled_y, scale_percent)) self.statusbar.set_filename(self.file_handler.get_page_filename()) if prefs['smart bg']: bg_colour = image.get_most_common_edge_colour(pixbuf) self.set_bg_colour(bg_colour) self._image_box.window.freeze_updates() self._main_layout.move(self._image_box, max(0, x_padding), max(0, y_padding)) self.left_image.show() if self.displayed_double(): self.right_image.show() else: self.right_image.hide() self._main_layout.set_size(*self._image_box.size_request()) if scroll: if at_bottom: self.scroll_to_fixed(horiz='endsecond', vert='bottom') else: self.scroll_to_fixed(horiz='startfirst', vert='top') self._image_box.window.thaw_updates() self.statusbar.set_root(self.file_handler.get_base_filename()) self.statusbar.update() self.update_title() while gtk.events_pending(): gtk.main_iteration(False) enhance.draw_histogram(self.left_image) self.file_handler.do_cacheing() self.thumbnailsidebar.load_thumbnails() return False