def _drag_begin(self, iconview, context): """Create a cursor image for drag-n-drop from the library. This method relies on implementation details regarding PIL's drawing functions and default font to produce good looking results. If those are changed in a future release of PIL, this method might produce bad looking output (e.g. non-centered text). It's also used with connect_after() to overwrite the cursor automatically created when using enable_model_drag_source(), so in essence it's a hack, but at least it works. """ icon_path = iconview.get_cursor()[0] num_books = len(iconview.get_selected_items()) book = self.get_book_at_path(icon_path) cover = self._library.backend.get_book_cover(book) if cover is None: cover = constants.MISSING_IMAGE_ICON cover = cover.scale_simple(max(0, cover.get_width() // 2), max(0, cover.get_height() // 2), prefs['scaling quality']) cover = image_tools.add_border(cover, 1, 0xFFFFFFFF) cover = image_tools.add_border(cover, 1) if num_books > 1: cover_width = cover.get_width() cover_height = cover.get_height() pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, max(30, cover_width + 15), max(30, cover_height + 10)) pointer.fill(0x00000000) cover.composite(pointer, 0, 0, cover_width, cover_height, 0, 0, 1, 1, prefs['scaling quality'], 255) im = Image.new('RGBA', (30, 30), 0x00000000) draw = ImageDraw.Draw(im) draw.polygon( (8, 0, 20, 0, 28, 8, 28, 20, 20, 28, 8, 28, 0, 20, 0, 8), fill=(0, 0, 0), outline=(0, 0, 0)) draw.polygon( (8, 1, 20, 1, 27, 8, 27, 20, 20, 27, 8, 27, 1, 20, 1, 8), fill=(128, 0, 0), outline=(255, 255, 255)) text = str(num_books) draw.text((15 - (6 * len(text) // 2), 9), text, fill=(255, 255, 255)) circle = image_tools.pil_to_pixbuf(im) circle.composite(pointer, max(0, cover_width - 15), max(0, cover_height - 20), 30, 30, max(0, cover_width - 15), max(0, cover_height - 20), 1, 1, prefs['scaling quality'], 255) else: pointer = cover context.set_icon_pixbuf(pointer, -5, -5)
def _drag_begin(self, iconview, context): """Create a cursor image for drag-n-drop from the library. This method relies on implementation details regarding PIL's drawing functions and default font to produce good looking results. If those are changed in a future release of PIL, this method might produce bad looking output (e.g. non-centered text). It's also used with connect_after() to overwrite the cursor automatically created when using enable_model_drag_source(), so in essence it's a hack, but at least it works. """ icon_path = iconview.get_cursor()[0] num_books = len(iconview.get_selected_items()) book = self.get_book_at_path(icon_path) cover = self._library.backend.get_book_cover(book) if cover is None: cover = image_tools.MISSING_IMAGE_ICON cover = cover.scale_simple(max(0, cover.get_width() // 2), max(0, cover.get_height() // 2), prefs['scaling quality']) cover = image_tools.add_border(cover, 1, 0xFFFFFFFF) cover = image_tools.add_border(cover, 1) if num_books > 1: cover_width = cover.get_width() cover_height = cover.get_height() pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, max(30, cover_width + 15), max(30, cover_height + 10)) pointer.fill(0x00000000) cover.composite(pointer, 0, 0, cover_width, cover_height, 0, 0, 1, 1, prefs['scaling quality'], 255) im = Image.new('RGBA', (30, 30), 0x00000000) draw = ImageDraw.Draw(im) draw.polygon( (8, 0, 20, 0, 28, 8, 28, 20, 20, 28, 8, 28, 0, 20, 0, 8), fill=(0, 0, 0), outline=(0, 0, 0)) draw.polygon( (8, 1, 20, 1, 27, 8, 27, 20, 20, 27, 8, 27, 1, 20, 1, 8), fill=(128, 0, 0), outline=(255, 255, 255)) text = str(num_books) draw.text((15 - (6 * len(text) // 2), 9), text, fill=(255, 255, 255)) circle = image_tools.pil_to_pixbuf(im) circle.composite(pointer, max(0, cover_width - 15), max(0, cover_height - 20), 30, 30, max(0, cover_width - 15), max(0, cover_height - 20), 1, 1, prefs['scaling quality'], 255) else: pointer = cover context.set_icon_pixbuf(pointer, -5, -5)
def _get_lens_pixbuf(self, x, y): """Get a pixbuf containing the appropiate image data for the lens where <x> and <y> are the positions of the cursor. """ canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, prefs['lens size'], prefs['lens size']) canvas.fill(0x000000bb) if self._window.displayed_double(): l_source_pixbuf, r_source_pixbuf = self._window.imagehandler.get_pixbufs(2) # XXX implied by self._window.displayed_double() == True if self._window.is_manga_mode: l_source_pixbuf, r_source_pixbuf = r_source_pixbuf, l_source_pixbuf l_image_size = self._window.images[0].size_request() # XXX transitional(double page limitation) r_image_size = self._window.images[1].size_request() # XXX transitional(double page limitation) self._add_subpixbuf(canvas, x, y, l_image_size, l_source_pixbuf, r_image_size[0], left=True) self._add_subpixbuf(canvas, x, y, r_image_size, r_source_pixbuf, l_image_size[0], left=False) else: source_pixbuf = self._window.imagehandler.get_pixbufs(1)[0] # XXX implied by self._window.displayed_double() == False image_size = self._window.images[0].size_request() # XXX transitional(double page limitation) self._add_subpixbuf(canvas, x, y, image_size, source_pixbuf) return image_tools.add_border(canvas, 1)
def _get_lens_pixbuf(self, x, y): """Get a pixbuf containing the appropiate image data for the lens where <x> and <y> are the positions of the cursor. """ canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, prefs['lens size'], prefs['lens size']) canvas.fill(0x000000bb) if self._window.displayed_double(): l_source_pixbuf, r_source_pixbuf = self._window.imagehandler.get_pixbufs() if self._window.is_manga_mode: l_source_pixbuf, r_source_pixbuf = r_source_pixbuf, l_source_pixbuf l_image_size = self._window.left_image.size_request() r_image_size = self._window.right_image.size_request() self._add_subpixbuf(canvas, x, y, l_image_size, l_source_pixbuf, r_image_size[0], left=True) self._add_subpixbuf(canvas, x, y, r_image_size, r_source_pixbuf, l_image_size[0], left=False) else: source_pixbuf = self._window.imagehandler.get_pixbufs()[0] image_size = self._window.left_image.size_request() self._add_subpixbuf(canvas, x, y, image_size, source_pixbuf) return image_tools.add_border(canvas, 1)
def _get_lens_pixbuf(self, x, y): """Get a pixbuf containing the appropiate image data for the lens where <x> and <y> are the positions of the cursor. """ canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, prefs["lens size"], prefs["lens size"]) canvas.fill(0x000000BB) if self._window.displayed_double(): l_source_pixbuf, r_source_pixbuf = self._window.imagehandler.get_pixbufs() if self._window.is_manga_mode: l_source_pixbuf, r_source_pixbuf = r_source_pixbuf, l_source_pixbuf l_image_size = self._window.left_image.size_request() r_image_size = self._window.right_image.size_request() self._add_subpixbuf(canvas, x, y, l_image_size, l_source_pixbuf, r_image_size[0], left=True) self._add_subpixbuf(canvas, x, y, r_image_size, r_source_pixbuf, l_image_size[0], left=False) else: source_pixbuf = self._window.imagehandler.get_pixbufs()[0] image_size = self._window.left_image.size_request() self._add_subpixbuf(canvas, x, y, image_size, source_pixbuf) return image_tools.add_border(canvas, 1)
def _get_pixbuf(self, uid): """ Get or create the thumbnail for the selected book <uid>. """ assert isinstance(uid, int) book = self._library.backend.get_book_by_id(uid) if self._cache.exists(book.path): pixbuf = self._cache.get(book.path) else: width, height = self._pixbuf_size(border_size=0) pixbuf = self._library.backend.get_book_thumbnail(book.path) or image_tools.MISSING_IMAGE_ICON pixbuf = image_tools.fit_in_rectangle(pixbuf, width, height, scale_up=True) pixbuf = image_tools.add_border(pixbuf, 1, 0xFFFFFFFF) self._cache.add(book.path, pixbuf) # Display indicator of having finished reading the book. # This information isn't cached in the pixbuf cache, as it changes frequently. # Anything smaller than 50px means that the status icon will not fit if prefs['library cover size'] < 50: return pixbuf last_read_page = book.get_last_read_page() if last_read_page is None or last_read_page != book.pages: return pixbuf # Composite icon on the lower right corner of the book cover pixbuf. book_pixbuf = self.render_icon(gtk.STOCK_APPLY, gtk.ICON_SIZE_LARGE_TOOLBAR) translation_x = pixbuf.get_width() - book_pixbuf.get_width() - 1 translation_y = pixbuf.get_height() - book_pixbuf.get_height() - 1 book_pixbuf.composite(pixbuf, translation_x, translation_y, book_pixbuf.get_width(), book_pixbuf.get_height(), translation_x, translation_y, 1.0, 1.0, gtk.gdk.INTERP_NEAREST, 0xFF) return pixbuf
def _generate_thumbnail(self, uid): """ Generate the pixbuf for C{path} at demand. """ assert isinstance(uid, int) page = uid pixbuf = self._window.imagehandler.get_thumbnail(page, prefs['thumbnail size'], prefs['thumbnail size'], nowait=True) if pixbuf is not None: pixbuf = image_tools.add_border(pixbuf, self._BORDER_SIZE) return pixbuf
def _get_pixbuf(self, uid): ''' Get or create the thumbnail for the selected book <uid>. ''' assert isinstance(uid, int) book = self._library.backend.get_book_by_id(uid) if self._cache.exists(book.path): pixbuf = self._cache.get(book.path) else: width, height = self._pixbuf_size(border_size=0) # cover thumbnail of book cover = self._library.backend.get_book_thumbnail(book.path) if not cover: cover = image_tools.MISSING_IMAGE_ICON cover = image_tools.fit_in_rectangle(cover, width - 2, height - 2, scale_up=True) cover = image_tools.add_border(cover, 1, 0xFFFFFFFF) src_width, src_height = cover.get_width(), cover.get_height() # icon background of book pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, width, height) pixbuf.fill(0x00000000) # full transparency offset_x = (width - src_width) // 2 offset_y = (height - src_height) // 2 cover.copy_area(0, 0, src_width, src_height, pixbuf, offset_x, offset_y) self._cache.add(book.path, pixbuf) # Display indicator of having finished reading the book. # This information isn't cached in the pixbuf cache # as it changes frequently. # Anything smaller than 50px means that the status icon will not fit if prefs['library cover size'] < 50: return pixbuf last_read_page = book.get_last_read_page() if last_read_page is None or last_read_page != book.pages: return pixbuf # Composite icon on the lower right corner of the book cover pixbuf. book_pixbuf = self.render_icon(Gtk.STOCK_APPLY, Gtk.IconSize.LARGE_TOOLBAR) translation_x = pixbuf.get_width() - book_pixbuf.get_width() - 1 translation_y = pixbuf.get_height() - book_pixbuf.get_height() - 1 book_pixbuf.composite(pixbuf, translation_x, translation_y, book_pixbuf.get_width(), book_pixbuf.get_height(), translation_x, translation_y, 1.0, 1.0, GdkPixbuf.InterpType.NEAREST, 0xFF) return pixbuf
def _get_pixbuf(self, path, model, model_path): """ Get or create the thumbnail for the selected book at <path>. """ if self._cache.exists(path): return self._cache.get(path) else: pixbuf = self._library.backend.get_book_thumbnail(path) or constants.MISSING_IMAGE_ICON # The ratio (0.67) is just above the normal aspect ratio for books. pixbuf = image_tools.fit_in_rectangle(pixbuf, int(0.67 * prefs['library cover size']), prefs['library cover size'], True) pixbuf = image_tools.add_border(pixbuf, 1, 0xFFFFFFFF) self._cache.add(path, pixbuf) return pixbuf
def _get_pixbuf(self, path): """ Get or create the thumbnail for the selected book at <path>. """ if self._cache.exists(path): return self._cache.get(path) else: pixbuf = self._library.backend.get_book_thumbnail( path) or constants.MISSING_IMAGE_ICON # The ratio (0.67) is just above the normal aspect ratio for books. pixbuf = image_tools.fit_in_rectangle( pixbuf, int(0.67 * prefs['library cover size']), prefs['library cover size'], True) pixbuf = image_tools.add_border(pixbuf, 1, 0xFFFFFFFF) self._cache.add(path, pixbuf) return pixbuf
def _get_lens_pixbuf(self, x, y): """Get a pixbuf containing the appropiate image data for the lens where <x> and <y> are the positions of the cursor. """ canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, prefs['lens size'], prefs['lens size']) canvas.fill(image_tools.convert_rgb16list_to_rgba8int(self._window.get_bg_colour())) cb = self._window.layout.get_content_boxes() source_pixbufs = self._window.imagehandler.get_pixbufs(len(cb)) for i in range(len(cb)): cpos = cb[i].get_position() self._add_subpixbuf(canvas, x - cpos[0], y - cpos[1], cb[i].get_size(), source_pixbufs[i]) return image_tools.add_border(canvas, 1)
def _generate_thumbnail(self, file_path, model, path): """ Generate the pixbuf for C{path} at demand. """ if isinstance(path, tuple): page = path[0] + 1 elif isinstance(path, int): page = path + 1 elif path is None: return constants.MISSING_IMAGE_ICON else: assert False, "Expected int or tuple as tree path." pixbuf = self._window.imagehandler.get_thumbnail(page, prefs['thumbnail size'], prefs['thumbnail size']) or \ constants.MISSING_IMAGE_ICON pixbuf = image_tools.add_border(pixbuf, 1) return pixbuf
def _get_lens_pixbuf(self, x, y): """Get a pixbuf containing the appropiate image data for the lens where <x> and <y> are the positions of the cursor. """ canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, prefs['lens size'], prefs['lens size']) canvas.fill( image_tools.convert_rgb16list_to_rgba8int( self._window.get_bg_colour())) cb = self._window.layout.get_content_boxes() source_pixbufs = self._window.imagehandler.get_pixbufs(len(cb)) for i in range(len(cb)): cpos = cb[i].get_position() self._add_subpixbuf(canvas, x - cpos[0], y - cpos[1], cb[i].get_size(), source_pixbufs[i]) return image_tools.add_border(canvas, 1)
def _preview_thumbnail_finished(self, filepath, pixbuf): ''' Called when the thumbnailer has finished creating the thumbnail for <filepath>. ''' if self._destroyed: return current_path = self.filechooser.get_preview_filename() if current_path and current_path == filepath: if pixbuf is None: self._preview_image.clear() self._namelabel.set_text('') self._sizelabel.set_text('') else: pixbuf = image_tools.add_border(pixbuf, 1) self._preview_image.set_from_pixbuf(pixbuf) self._namelabel.set_text(os.path.basename(filepath)) self._sizelabel.set_text( tools.format_byte_size(os.stat(filepath).st_size))
def _get_lens_pixbuf(self, x, y): '''Get a pixbuf containing the appropiate image data for the lens where <x> and <y> are the positions of the cursor. ''' canvas = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB, has_alpha=True, bits_per_sample=8, width=prefs['lens size'], height=prefs['lens size']) r, g, b, a = [int(p * 255) for p in self._window.get_bg_color()] canvas.fill(image_tools.convert_rgb16list_to_rgba8int([r, g, b])) cb = self._window.layout.get_content_boxes() source_pixbufs = self._window.imagehandler.get_pixbufs(len(cb)) for i in range(len(cb)): if image_tools.is_animation(source_pixbufs[i]): continue cpos = cb[i].get_position() self._add_subpixbuf(canvas, x - cpos[0], y - cpos[1], cb[i].get_size(), source_pixbufs[i]) return image_tools.add_border(canvas, 1)
def _preview_thumbnail_finished(self, filepath, pixbuf): """ Called when the thumbnailer has finished creating the thumbnail for <filepath>. """ if self._destroyed: return current_path = self.filechooser.get_preview_filename() if current_path and current_path.decode('utf-8') == filepath: if pixbuf is None: self._preview_image.clear() self._namelabel.set_text('') self._sizelabel.set_text('') else: pixbuf = image_tools.add_border(pixbuf, 1) self._preview_image.set_from_pixbuf(pixbuf) self._namelabel.set_text(os.path.basename(filepath)) self._sizelabel.set_text( '%.1f KiB' % (os.stat(filepath).st_size / 1024.0))
def _get_pixbuf(self, path, model, model_path): """ Get or create the thumbnail for the selected book at <path>. """ if self._cache.exists(path): pixbuf = self._cache.get(path) else: pixbuf = self._library.backend.get_book_thumbnail( path) or constants.MISSING_IMAGE_ICON # The ratio (0.67) is just above the normal aspect ratio for books. pixbuf = image_tools.fit_in_rectangle( pixbuf, int(0.67 * prefs['library cover size']), prefs['library cover size'], True) pixbuf = image_tools.add_border(pixbuf, 1, 0xFFFFFFFF) self._cache.add(path, pixbuf) # Display indicator of having finished reading the book. # This information isn't cached in the pixbuf cache, as it changes frequently. # Anything smaller than 50px means that the status icon will not fit if prefs['library cover size'] < 50: return pixbuf book = self._library.backend.get_book_by_path(path) last_read_page = book.get_last_read_page() if last_read_page is None or last_read_page != book.pages: return pixbuf if last_read_page == book.pages: book_pixbuf = self.render_icon(gtk.STOCK_APPLY, gtk.ICON_SIZE_LARGE_TOOLBAR) # Composite icon on the lower right corner of the book cover pixbuf. translation_x = pixbuf.get_width() - book_pixbuf.get_width() - 1 translation_y = pixbuf.get_height() - book_pixbuf.get_height() - 1 book_pixbuf.composite(pixbuf, translation_x, translation_y, book_pixbuf.get_width(), book_pixbuf.get_height(), translation_x, translation_y, 1.0, 1.0, gtk.gdk.INTERP_NEAREST, 0xFF) return pixbuf
def _get_pixbuf(self, uid): """ Get or create the thumbnail for the selected book <uid>. """ assert isinstance(uid, int) book = self._library.backend.get_book_by_id(uid) if self._cache.exists(book.path): pixbuf = self._cache.get(book.path) else: width, height = self._pixbuf_size(border_size=0) pixbuf = self._library.backend.get_book_thumbnail( book.path) or image_tools.MISSING_IMAGE_ICON pixbuf = image_tools.fit_in_rectangle(pixbuf, width, height, scale_up=True) pixbuf = image_tools.add_border(pixbuf, 1, 0xFFFFFFFF) self._cache.add(book.path, pixbuf) # Display indicator of having finished reading the book. # This information isn't cached in the pixbuf cache, as it changes frequently. # Anything smaller than 50px means that the status icon will not fit if prefs['library cover size'] < 50: return pixbuf last_read_page = book.get_last_read_page() if last_read_page is None or last_read_page != book.pages: return pixbuf # Composite icon on the lower right corner of the book cover pixbuf. book_pixbuf = self.render_icon(Gtk.STOCK_APPLY, Gtk.IconSize.LARGE_TOOLBAR) translation_x = pixbuf.get_width() - book_pixbuf.get_width() - 1 translation_y = pixbuf.get_height() - book_pixbuf.get_height() - 1 book_pixbuf.composite(pixbuf, translation_x, translation_y, book_pixbuf.get_width(), book_pixbuf.get_height(), translation_x, translation_y, 1.0, 1.0, GdkPixbuf.InterpType.NEAREST, 0xFF) return pixbuf
def cache_thumbnails(self, pages): """ Done by worker threads to create pixbufs for the pages passed into <pages>. """ while not self._stop_cacheing and not pages.empty(): try: page = pages.get_nowait() except Queue.Empty: break pixbuf = self._window.imagehandler.get_thumbnail(page, prefs['thumbnail size'], prefs['thumbnail size']) or \ constants.MISSING_IMAGE_ICON pixbuf = image_tools.add_border(pixbuf, 1) pages.task_done() if not self._stop_cacheing: self.thumbnail_loaded(page, pixbuf) if not self._stop_cacheing: pages.join() self._loaded = True self._is_loading = False
def _get_pixbuf(self, path, model, model_path): """ Get or create the thumbnail for the selected book at <path>. """ if self._cache.exists(path): pixbuf = self._cache.get(path) else: pixbuf = self._library.backend.get_book_thumbnail(path) or constants.MISSING_IMAGE_ICON # The ratio (0.67) is just above the normal aspect ratio for books. pixbuf = image_tools.fit_in_rectangle(pixbuf, int(0.67 * prefs['library cover size']), prefs['library cover size'], True) pixbuf = image_tools.add_border(pixbuf, 1, 0xFFFFFFFF) self._cache.add(path, pixbuf) # Display indicator of having finished reading the book. # This information isn't cached in the pixbuf cache, as it changes frequently. # Anything smaller than 50px means that the status icon will not fit if prefs['library cover size'] < 50: return pixbuf book = self._library.backend.get_book_by_path(path) last_read_page = book.get_last_read_page() if last_read_page is None or last_read_page != book.pages: return pixbuf if last_read_page == book.pages: book_pixbuf = self.render_icon(gtk.STOCK_APPLY, gtk.ICON_SIZE_LARGE_TOOLBAR) # Composite icon on the lower right corner of the book cover pixbuf. translation_x = pixbuf.get_width() - book_pixbuf.get_width() - 1 translation_y = pixbuf.get_height() - book_pixbuf.get_height() - 1 book_pixbuf.composite(pixbuf, translation_x, translation_y, book_pixbuf.get_width(), book_pixbuf.get_height(), translation_x, translation_y, 1.0, 1.0, gtk.gdk.INTERP_NEAREST, 0xFF) return pixbuf
def set_thumbnail(self, pixbuf): pixbuf = image_tools.add_border(pixbuf, 1) self._thumb.set_from_pixbuf(pixbuf)