def trim_cover(self): book_id = self.data.get('id') if not book_id: return from calibre.utils.img import image_from_x, remove_borders_from_image img = image_from_x(self.pixmap) nimg = remove_borders_from_image(img) if nimg is not img: self.last_trim_id = book_id self.last_trim_pixmap = self.pixmap self.update_cover(QPixmap.fromImage(nimg))
def process_result(log, result): plugin, data = result try: if getattr(plugin, 'auto_trim_covers', False): img = image_from_data(data) nimg = remove_borders_from_image(img) if nimg is not img: data = image_to_data(nimg) fmt, width, height = identify(data) if width < 0 or height < 0: raise ValueError('Could not read cover image dimensions') if width < 50 or height < 50: raise ValueError('Image too small') data = save_cover_data_to(data) except Exception: log.exception('Invalid cover from', plugin.name) return None return (plugin, width, height, fmt, data)
def process_pages(self): from calibre.utils.img import ( image_to_data, rotate_image, remove_borders_from_image, normalize_image, add_borders_to_image, resize_image, gaussian_sharpen_image, grayscale_image, despeckle_image, quantize_image ) for i, img in enumerate(self.pages): if self.rotate: img = rotate_image(img, -90) if not self.opts.disable_trim: img = remove_borders_from_image(img) # Do the Photoshop "Auto Levels" equivalent if not self.opts.dont_normalize: img = normalize_image(img) sizex, sizey = img.width(), img.height() SCRWIDTH, SCRHEIGHT = self.opts.output_profile.comic_screen_size try: if self.opts.comic_image_size: SCRWIDTH, SCRHEIGHT = map(int, [x.strip() for x in self.opts.comic_image_size.split('x')]) except: pass # Ignore if self.opts.keep_aspect_ratio: # Preserve the aspect ratio by adding border aspect = float(sizex) / float(sizey) if aspect <= (float(SCRWIDTH) / float(SCRHEIGHT)): newsizey = SCRHEIGHT newsizex = int(newsizey * aspect) deltax = (SCRWIDTH - newsizex) / 2 deltay = 0 else: newsizex = SCRWIDTH newsizey = int(newsizex / aspect) deltax = 0 deltay = (SCRHEIGHT - newsizey) / 2 if newsizex < MAX_SCREEN_SIZE and newsizey < MAX_SCREEN_SIZE: # Too large and resizing fails, so better # to leave it as original size img = resize_image(img, newsizex, newsizey) img = add_borders_to_image(img, left=deltax, right=deltax, top=deltay, bottom=deltay) elif self.opts.wide: # Keep aspect and Use device height as scaled image width so landscape mode is clean aspect = float(sizex) / float(sizey) screen_aspect = float(SCRWIDTH) / float(SCRHEIGHT) # Get dimensions of the landscape mode screen # Add 25px back to height for the battery bar. wscreenx = SCRHEIGHT + 25 wscreeny = int(wscreenx / screen_aspect) if aspect <= screen_aspect: newsizey = wscreeny newsizex = int(newsizey * aspect) deltax = (wscreenx - newsizex) / 2 deltay = 0 else: newsizex = wscreenx newsizey = int(newsizex / aspect) deltax = 0 deltay = (wscreeny - newsizey) / 2 if newsizex < MAX_SCREEN_SIZE and newsizey < MAX_SCREEN_SIZE: # Too large and resizing fails, so better # to leave it as original size img = resize_image(img, newsizex, newsizey) img = add_borders_to_image(img, left=deltax, right=deltax, top=deltay, bottom=deltay) else: if SCRWIDTH < MAX_SCREEN_SIZE and SCRHEIGHT < MAX_SCREEN_SIZE: img = resize_image(img, SCRWIDTH, SCRHEIGHT) if not self.opts.dont_sharpen: img = gaussian_sharpen_image(img, 0.0, 1.0) if not self.opts.dont_grayscale: img = grayscale_image(img) if self.opts.despeckle: img = despeckle_image(img) if self.opts.output_format.lower() == 'png' and self.opts.colors: img = quantize_image(img, max_colors=min(256, self.opts.colors)) dest = '%d_%d.%s'%(self.num, i, self.opts.output_format) dest = os.path.join(self.dest, dest) with lopen(dest, 'wb') as f: f.write(image_to_data(img, fmt=self.opts.output_format)) self.append(dest)
def remove_border(self, fuzz=None): if fuzz is not None and fuzz < 0 or fuzz > 255: fuzz = None self.img = remove_borders_from_image(self.img, fuzz)
def __call__(self, canvas): return remove_borders_from_image(canvas.current_image)
def process_pages(self): from calibre.utils.img import (image_to_data, rotate_image, remove_borders_from_image, normalize_image, add_borders_to_image, resize_image, gaussian_sharpen_image, grayscale_image, despeckle_image, quantize_image) for i, img in enumerate(self.pages): if self.rotate: img = rotate_image(img, -90) if not self.opts.disable_trim: img = remove_borders_from_image(img) # Do the Photoshop "Auto Levels" equivalent if not self.opts.dont_normalize: img = normalize_image(img) sizex, sizey = img.width(), img.height() SCRWIDTH, SCRHEIGHT = self.opts.output_profile.comic_screen_size try: if self.opts.comic_image_size: SCRWIDTH, SCRHEIGHT = map(int, [ x.strip() for x in self.opts.comic_image_size.split('x') ]) except: pass # Ignore if self.opts.keep_aspect_ratio: # Preserve the aspect ratio by adding border aspect = float(sizex) / float(sizey) if aspect <= (float(SCRWIDTH) / float(SCRHEIGHT)): newsizey = SCRHEIGHT newsizex = int(newsizey * aspect) deltax = (SCRWIDTH - newsizex) // 2 deltay = 0 else: newsizex = SCRWIDTH newsizey = int(newsizex // aspect) deltax = 0 deltay = (SCRHEIGHT - newsizey) // 2 if newsizex < MAX_SCREEN_SIZE and newsizey < MAX_SCREEN_SIZE: # Too large and resizing fails, so better # to leave it as original size img = resize_image(img, newsizex, newsizey) img = add_borders_to_image(img, left=deltax, right=deltax, top=deltay, bottom=deltay) elif self.opts.wide: # Keep aspect and Use device height as scaled image width so landscape mode is clean aspect = float(sizex) / float(sizey) screen_aspect = float(SCRWIDTH) / float(SCRHEIGHT) # Get dimensions of the landscape mode screen # Add 25px back to height for the battery bar. wscreenx = SCRHEIGHT + 25 wscreeny = int(wscreenx // screen_aspect) if aspect <= screen_aspect: newsizey = wscreeny newsizex = int(newsizey * aspect) deltax = (wscreenx - newsizex) // 2 deltay = 0 else: newsizex = wscreenx newsizey = int(newsizex // aspect) deltax = 0 deltay = (wscreeny - newsizey) // 2 if newsizex < MAX_SCREEN_SIZE and newsizey < MAX_SCREEN_SIZE: # Too large and resizing fails, so better # to leave it as original size img = resize_image(img, newsizex, newsizey) img = add_borders_to_image(img, left=deltax, right=deltax, top=deltay, bottom=deltay) else: if SCRWIDTH < MAX_SCREEN_SIZE and SCRHEIGHT < MAX_SCREEN_SIZE: img = resize_image(img, SCRWIDTH, SCRHEIGHT) if not self.opts.dont_sharpen: img = gaussian_sharpen_image(img, 0.0, 1.0) if not self.opts.dont_grayscale: img = grayscale_image(img) if self.opts.despeckle: img = despeckle_image(img) if self.opts.output_format.lower() == 'png' and self.opts.colors: img = quantize_image(img, max_colors=min(256, self.opts.colors)) dest = '%d_%d.%s' % (self.num, i, self.opts.output_format) dest = os.path.join(self.dest, dest) with lopen(dest, 'wb') as f: f.write(image_to_data(img, fmt=self.opts.output_format)) self.append(dest)
def do_all(self): cache = self.db.new_api args = self.args # Title and authors if args.do_swap_ta: title_map = cache.all_field_for('title', self.ids) authors_map = cache.all_field_for('authors', self.ids) def new_title(authors): ans = authors_to_string(authors) return titlecase(ans) if args.do_title_case else ans new_title_map = {bid:new_title(authors) for bid, authors in authors_map.iteritems()} new_authors_map = {bid:string_to_authors(title) for bid, title in title_map.iteritems()} cache.set_field('authors', new_authors_map) cache.set_field('title', new_title_map) if args.do_title_case and not args.do_swap_ta: title_map = cache.all_field_for('title', self.ids) cache.set_field('title', {bid:titlecase(title) for bid, title in title_map.iteritems()}) if args.do_title_sort: lang_map = cache.all_field_for('languages', self.ids) title_map = cache.all_field_for('title', self.ids) def get_sort(book_id): if args.languages: lang = args.languages[0] else: try: lang = lang_map[book_id][0] except (KeyError, IndexError, TypeError, AttributeError): lang = 'eng' return title_sort(title_map[book_id], lang=lang) cache.set_field('sort', {bid:get_sort(bid) for bid in self.ids}) if args.au: authors = string_to_authors(args.au) cache.set_field('authors', {bid:authors for bid in self.ids}) if args.do_auto_author: aus_map = cache.author_sort_strings_for_books(self.ids) cache.set_field('author_sort', {book_id:' & '.join(aus_map[book_id]) for book_id in aus_map}) if args.aus and args.do_aus: cache.set_field('author_sort', {bid:args.aus for bid in self.ids}) # Covers if args.cover_action == 'remove': cache.set_cover({bid:None for bid in self.ids}) elif args.cover_action == 'generate': from calibre.ebooks.covers import generate_cover for book_id in self.ids: mi = self.db.get_metadata(book_id, index_is_id=True) cdata = generate_cover(mi, prefs=args.generate_cover_settings) cache.set_cover({book_id:cdata}) elif args.cover_action == 'fromfmt': for book_id in self.ids: fmts = cache.formats(book_id, verify_formats=False) if fmts: covers = [] for fmt in fmts: fmtf = cache.format(book_id, fmt, as_file=True) if fmtf is None: continue cdata, area = get_cover_data(fmtf, fmt) if cdata: covers.append((cdata, area)) covers.sort(key=lambda x: x[1]) if covers: cache.set_cover({book_id:covers[-1][0]}) elif args.cover_action == 'trim': from calibre.utils.img import remove_borders_from_image, image_to_data, image_from_data for book_id in self.ids: cdata = cache.cover(book_id) if cdata: img = image_from_data(cdata) nimg = remove_borders_from_image(img) if nimg is not img: cdata = image_to_data(nimg) cache.set_cover({book_id:cdata}) elif args.cover_action == 'clone': cdata = None for book_id in self.ids: cdata = cache.cover(book_id) if cdata: break if cdata: cache.set_cover({bid:cdata for bid in self.ids if bid != book_id}) # Formats if args.do_remove_format: cache.remove_formats({bid:(args.remove_format,) for bid in self.ids}) if args.restore_original: for book_id in self.ids: formats = cache.formats(book_id) originals = tuple(x.upper() for x in formats if x.upper().startswith('ORIGINAL_')) for ofmt in originals: cache.restore_original_format(book_id, ofmt) # Various fields if args.rating != -1: cache.set_field('rating', {bid:args.rating*2 for bid in self.ids}) if args.clear_pub: cache.set_field('publisher', {bid:'' for bid in self.ids}) if args.pub: cache.set_field('publisher', {bid:args.pub for bid in self.ids}) if args.clear_series: cache.set_field('series', {bid:'' for bid in self.ids}) if args.pubdate is not None: cache.set_field('pubdate', {bid:args.pubdate for bid in self.ids}) if args.adddate is not None: cache.set_field('timestamp', {bid:args.adddate for bid in self.ids}) if args.do_series: sval = args.series_start_value if args.do_series_restart else cache.get_next_series_num_for(args.series, current_indices=True) cache.set_field('series', {bid:args.series for bid in self.ids}) if not args.series: cache.set_field('series_index', {bid:1.0 for bid in self.ids}) else: def next_series_num(bid, i): if args.do_series_restart: return sval + (i * args.series_increment) next_num = _get_next_series_num_for_list(sorted(sval.itervalues()), unwrap=False) sval[bid] = next_num return next_num smap = {bid:next_series_num(bid, i) for i, bid in enumerate(self.ids)} if args.do_autonumber: cache.set_field('series_index', smap) elif tweaks['series_index_auto_increment'] != 'no_change': cache.set_field('series_index', {bid:1.0 for bid in self.ids}) if args.comments is not null: cache.set_field('comments', {bid:args.comments for bid in self.ids}) if args.do_remove_conv: cache.delete_conversion_options(self.ids) if args.clear_languages: cache.set_field('languages', {bid:() for bid in self.ids}) elif args.languages: cache.set_field('languages', {bid:args.languages for bid in self.ids}) if args.remove_all: cache.set_field('tags', {bid:() for bid in self.ids}) if args.add or args.remove: self.db.bulk_modify_tags(self.ids, add=args.add, remove=args.remove) if self.do_sr: for book_id in self.ids: self.s_r_func(book_id) if self.sr_calls: for field, book_id_val_map in self.sr_calls.iteritems(): self.refresh_books.update(self.db.new_api.set_field(field, book_id_val_map))