def add_quick_start_guide(library_view, refresh_cover_browser=None): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks import calibre_cover from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or 'eng' gprefs['quick_start_guide_added'] = True imgbuf = BytesIO(calibre_cover(_('Quick Start Guide'), '', author_size=8)) try: with open(P('quick_start/%s.epub' % l), 'rb') as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with open(P('quick_start/eng.epub'), 'rb') as src: buf = BytesIO(src.read()) safe_replace(buf, 'images/cover.jpg', imgbuf) buf.seek(0) mi = get_metadata(buf, 'epub') with PersistentTemporaryFile('.epub') as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ['epub'], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if refresh_cover_browser is not None: refresh_cover_browser() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def default_cover(self): ''' Create a generic cover for books that dont have a cover ''' from calibre.ebooks.metadata import authors_to_string, fmt_sidx if self.no_default_cover: return None self.log('Generating default cover') m = self.oeb.metadata title = unicode(m.title[0]) authors = [unicode(x) for x in m.creator if x.role == 'aut'] series_string = None if m.series and m.series_index: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(m.series_index[0], use_roman=True), series=unicode(m.series[0])) try: from calibre.ebooks import calibre_cover img_data = calibre_cover(title, authors_to_string(authors), series_string=series_string) id, href = self.oeb.manifest.generate('cover', u'cover_image.jpg') item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0], data=img_data) m.clear('cover') m.add('cover', item.id) return item.href except: self.log.exception('Failed to generate default cover') return None
def add_quick_start_guide(library_view, db_images): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks import calibre_cover from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or "eng" gprefs["quick_start_guide_added"] = True imgbuf = BytesIO(calibre_cover(_("Quick Start Guide"), "", author_size=8)) try: with open(P("quick_start/%s.epub" % l), "rb") as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with open(P("quick_start/eng.epub"), "rb") as src: buf = BytesIO(src.read()) safe_replace(buf, "images/cover.jpg", imgbuf) buf.seek(0) mi = get_metadata(buf, "epub") with PersistentTemporaryFile(".epub") as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ["epub"], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if hasattr(db_images, "reset"): db_images.reset() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def default_cover(self): ''' Create a generic cover for books that dont have a cover ''' from calibre.ebooks.metadata import authors_to_string, fmt_sidx if self.no_default_cover: return None self.log('Generating default cover') m = self.oeb.metadata title = unicode(m.title[0]) authors = [unicode(x) for x in m.creator if x.role == 'aut'] series_string = None if m.series and m.series_index: series_string = _('Book %(sidx)s of %(series)s') % dict( sidx=fmt_sidx(m.series_index[0], use_roman=True), series=unicode(m.series[0])) try: from calibre.ebooks import calibre_cover img_data = calibre_cover(title, authors_to_string(authors), series_string=series_string) id, href = self.oeb.manifest.generate('cover', u'cover_image.jpg') item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0], data=img_data) m.clear('cover') m.add('cover', item.id) return item.href except: self.log.exception('Failed to generate default cover') return None
def replace_wmf(self, name): from calibre.ebooks import calibre_cover if self.default_img is None: self.default_img = calibre_cover('Conversion of WMF images is not supported', 'Use Microsoft Word or OpenOffice to save this RTF file' ' as HTML and convert that in calibre.', title_size=36, author_size=20) name = name.replace('.wmf', '.jpg') with open(name, 'wb') as f: f.write(self.default_img) return name
def test_imaging(): from calibre.ebooks import calibre_cover data = calibre_cover('test', 'ok') if len(data) > 1000: print ('ImageMagick OK!') else: raise RuntimeError('ImageMagick choked!') from PIL import Image i = Image.open(cStringIO.StringIO(data)) if i.size < (20, 20): raise RuntimeError('PIL choked!') print ('PIL OK!')
def test_imaging(): from calibre.ebooks import calibre_cover data = calibre_cover('test', 'ok') if len(data) > 1000: print('ImageMagick OK!') else: raise RuntimeError('ImageMagick choked!') from PIL import Image i = Image.open(cStringIO.StringIO(data)) if i.size < (20, 20): raise RuntimeError('PIL choked!') print('PIL OK!')
def replace_wmf(self, name): from calibre.ebooks import calibre_cover if self.default_img is None: self.default_img = calibre_cover( 'Conversion of WMF images is not supported', 'Use Microsoft Word or OpenOffice to save this RTF file' ' as HTML and convert that in calibre.', title_size=36, author_size=20) name = name.replace('.wmf', '.jpg') with open(name, 'wb') as f: f.write(self.default_img) return name
def default_cover(self, cover_file): """ Create a generic cover for recipes that don't have a cover This override adds time to the cover """ try: from calibre.ebooks import calibre_cover title = self.title if isinstance(self.title, unicode) else \ self.title.decode('utf-8', 'replace') date = strftime(self.timefmt) time = strftime('[%I:%M %p]') img_data = calibre_cover(title, date, time) cover_file.write(img_data) cover_file.flush() except: self.log.exception('Failed to generate default cover') return False return True
def upload_cover(self, path, filename, metadata, filepath): from calibre.ebooks import calibre_cover from calibre.utils.magick.draw import thumbnail coverdata = getattr(metadata, 'thumbnail', None) if coverdata and coverdata[2]: cover = coverdata[2] else: cover = calibre_cover(metadata.get('title', _('Unknown')), metadata.get('authors', _('Unknown'))) cover = thumbnail(cover, width=self.THUMBNAIL_HEIGHT, height=self.THUMBNAIL_HEIGHT, fmt='png')[-1] cpath = self.alex_cpath(os.path.join(path, filename)) cdir = os.path.dirname(cpath) if not os.path.exists(cdir): os.makedirs(cdir) with open(cpath, 'wb') as coverfile: coverfile.write(cover)
def generate_cover(self, *args): from calibre.ebooks import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config title = self.dialog.title.current_val author = authors_to_string(self.dialog.authors.current_val) if not title or not author: return error_dialog(self, _('Specify title and author'), _('You must specify a title and author before generating ' 'a cover'), show=True) series = self.dialog.series.current_val series_string = None if series: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(self.dialog.series_index.current_val, use_roman=config['use_roman_numerals_for_series_number']), series=series) self.current_val = calibre_cover(title, author, series_string=series_string)
def test_imaging(): from calibre.ebooks import calibre_cover data = calibre_cover("test", "ok") if len(data) > 1000: print("ImageMagick OK!") else: raise RuntimeError("ImageMagick choked!") from PIL import Image try: import _imaging, _imagingmath, _imagingft _imaging, _imagingmath, _imagingft except ImportError: from PIL import _imaging, _imagingmath, _imagingft _imaging, _imagingmath, _imagingft i = Image.open(cStringIO.StringIO(data)) if i.size < (20, 20): raise RuntimeError("PIL choked!") print("PIL OK!")
def upload_cover(self, path, filename, metadata, filepath): from calibre.ebooks import calibre_cover from calibre.utils.magick.draw import thumbnail coverdata = getattr(metadata, 'thumbnail', None) if coverdata and coverdata[2]: cover = coverdata[2] else: cover = calibre_cover(metadata.get('title', _('Unknown')), metadata.get('authors', _('Unknown'))) cover = thumbnail(cover, width=self.THUMBNAIL_HEIGHT, height=self.THUMBNAIL_HEIGHT, fmt='png')[-1] cpath = self.alex_cpath(os.path.join(path, filename)) cdir = os.path.dirname(cpath) if not os.path.exists(cdir): os.makedirs(cdir) with open(cpath, 'wb') as coverfile: coverfile.write(cover) fsync(coverfile)
def generate_cover(self, *args): from calibre.ebooks import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config title = self.dialog.title.current_val author = authors_to_string(self.dialog.authors.current_val) if not title or not author: return error_dialog( self, _('Specify title and author'), _('You must specify a title and author before generating ' 'a cover'), show=True) series = self.dialog.series.current_val series_string = None if series: series_string = _('Book %(sidx)s of %(series)s') % dict( sidx=fmt_sidx( self.dialog.series_index.current_val, use_roman=config['use_roman_numerals_for_series_number']), series=series) self.current_val = calibre_cover(title, author, series_string=series_string)
if cpath and os.path.exists(cpath): existing_cover = True except: pass if self.opts.use_existing_cover and not existing_cover: log.warning("no existing catalog cover found") if self.opts.use_existing_cover and existing_cover: recommendations.append( ('cover', cpath, OptionRecommendation.HIGH)) log.info("using existing catalog cover") else: log.info("replacing catalog cover") new_cover_path = PersistentTemporaryFile(suffix='.jpg') new_cover = calibre_cover( opts.catalog_title.replace('"', '\\"'), 'calibre') new_cover_path.write(new_cover) new_cover_path.close() recommendations.append( ('cover', new_cover_path.name, OptionRecommendation.HIGH)) # Run ebook-convert from calibre.ebooks.conversion.plumber import Plumber plumber = Plumber(os.path.join(catalog.catalog_path, opts.basename + '.opf'), path_to_output, log, report_progress=notification, abort_after_input_dump=False) plumber.merge_ui_recommendations(recommendations) plumber.run()
cpath = db.cover(matches[0], index_is_id=True, as_path=True) if cpath and os.path.exists(cpath): existing_cover = True except: pass if self.opts.use_existing_cover and not existing_cover: log.warning("no existing catalog cover found") if self.opts.use_existing_cover and existing_cover: recommendations.append(('cover', cpath, OptionRecommendation.HIGH)) log.info("using existing catalog cover") else: log.info("replacing catalog cover") new_cover_path = PersistentTemporaryFile(suffix='.jpg') new_cover = calibre_cover(opts.catalog_title.replace('"', '\\"'), 'calibre') new_cover_path.write(new_cover) new_cover_path.close() recommendations.append(('cover', new_cover_path.name, OptionRecommendation.HIGH)) # Run ebook-convert from calibre.ebooks.conversion.plumber import Plumber plumber = Plumber(os.path.join(catalog.catalog_path, opts.basename + '.opf'), path_to_output, log, report_progress=notification, abort_after_input_dump=False) plumber.merge_ui_recommendations(recommendations) plumber.run() try: os.remove(cpath) except:
def do_one(self, id): remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, \ do_autonumber, do_remove_format, remove_format, do_swap_ta, \ do_remove_conv, do_auto_author, series, do_series_restart, \ series_start_value, do_title_case, cover_action, clear_series, \ pubdate, adddate, do_title_sort, languages, clear_languages, \ restore_original = self.args # first loop: All changes that modify the filesystem and commit # immediately. We want to # try hard to keep the DB and the file system in sync, even in the face # of exceptions or forced exits. if self.current_phase == 1: title_set = False if do_swap_ta: title = self.db.title(id, index_is_id=True) aum = self.db.authors(id, index_is_id=True) if aum: aum = [a.strip().replace('|', ',') for a in aum.split(',')] new_title = authors_to_string(aum) if do_title_case: new_title = titlecase(new_title) self.db.set_title(id, new_title, notify=False) title_set = True if title: new_authors = string_to_authors(title) self.db.set_authors(id, new_authors, notify=False) if do_title_case and not title_set: title = self.db.title(id, index_is_id=True) self.db.set_title(id, titlecase(title), notify=False) if do_title_sort: title = self.db.title(id, index_is_id=True) if languages: lang = languages[0] else: lang = self.db.languages(id, index_is_id=True) if lang: lang = lang.partition(',')[0] self.db.set_title_sort(id, title_sort(title, lang=lang), notify=False) if au: self.db.set_authors(id, string_to_authors(au), notify=False) if cover_action == 'remove': self.db.remove_cover(id) elif cover_action == 'generate': from calibre.ebooks import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config mi = self.db.get_metadata(id, index_is_id=True) series_string = None if mi.series: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(mi.series_index, use_roman=config['use_roman_numerals_for_series_number']), series=mi.series) cdata = calibre_cover(mi.title, mi.format_field('authors')[-1], series_string=series_string) self.db.set_cover(id, cdata) elif cover_action == 'fromfmt': fmts = self.db.formats(id, index_is_id=True, verify_formats=False) if fmts: covers = [] for fmt in fmts.split(','): fmtf = self.db.format(id, fmt, index_is_id=True, 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: self.db.set_cover(id, covers[-1][0]) covers = [] if do_remove_format: self.db.remove_format(id, remove_format, index_is_id=True, notify=False, commit=True) if restore_original: formats = self.db.formats(id, index_is_id=True) formats = formats.split(',') if formats else [] originals = [x.upper() for x in formats if x.upper().startswith('ORIGINAL_')] for ofmt in originals: fmt = ofmt.replace('ORIGINAL_', '') with SpooledTemporaryFile(SPOOL_SIZE) as stream: self.db.copy_format_to(id, ofmt, stream, index_is_id=True) stream.seek(0) self.db.add_format(id, fmt, stream, index_is_id=True, notify=False) self.db.remove_format(id, ofmt, index_is_id=True, notify=False, commit=True) elif self.current_phase == 2: # All of these just affect the DB, so we can tolerate a total rollback if do_auto_author: x = self.db.author_sort_from_book(id, index_is_id=True) if x: self.db.set_author_sort(id, x, notify=False, commit=False) if aus and do_aus: self.db.set_author_sort(id, aus, notify=False, commit=False) if rating != -1: self.db.set_rating(id, 2*rating, notify=False, commit=False) if pub: self.db.set_publisher(id, pub, notify=False, commit=False) if clear_series: self.db.set_series(id, '', notify=False, commit=False) if pubdate is not None: self.db.set_pubdate(id, pubdate, notify=False, commit=False) if adddate is not None: self.db.set_timestamp(id, adddate, notify=False, commit=False) if do_series: if do_series_restart: if self.series_start_value is None: self.series_start_value = series_start_value next = self.series_start_value self.series_start_value += 1 else: next = self.db.get_next_series_num_for(series) self.db.set_series(id, series, notify=False, commit=False) if not series: self.db.set_series_index(id, 1.0, notify=False, commit=False) elif do_autonumber: # is True if do_series_restart is True self.db.set_series_index(id, next, notify=False, commit=False) elif tweaks['series_index_auto_increment'] != 'no_change': self.db.set_series_index(id, 1.0, notify=False, commit=False) if do_remove_conv: self.db.delete_conversion_options(id, 'PIPE', commit=False) if clear_languages: self.db.set_languages(id, [], notify=False, commit=False) elif languages: self.db.set_languages(id, languages, notify=False, commit=False) elif self.current_phase == 3: # both of these are fast enough to just do them all for w in self.cc_widgets: w.commit(self.ids) if remove_all: self.db.remove_all_tags(self.ids) self.db.bulk_modify_tags(self.ids, add=add, remove=remove, notify=False) self.current_index = len(self.ids) elif self.current_phase == 4: self.s_r_func(id) # do the next one self.current_index += 1 self.do_one_signal.emit()
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 import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config for book_id in self.ids: mi = self.db.get_metadata(book_id, index_is_id=True) series_string = None if mi.series: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(mi.series_index, use_roman=config['use_roman_numerals_for_series_number']), series=mi.series) cdata = calibre_cover(mi.title, mi.format_field('authors')[-1], series_string=series_string) 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.magick import Image for book_id in self.ids: cdata = cache.cover(book_id) if cdata: im = Image() im.load(cdata) im.trim(tweaks['cover_trim_fuzz_value']) cdata = im.export('jpg') 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 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))