diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 8af6cdfcd0..4b468c3ace 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -384,14 +384,6 @@ maximum_resort_levels = 5 # the fields that are being displayed. sort_dates_using_visible_fields = False -#: Specify which font to use when generating a default cover or masthead -# Absolute path to .ttf font files to use as the fonts for the title, author -# and footer when generating a default cover or masthead image. Useful if the -# default font (Liberation Serif) does not contain glyphs for the language of -# the books in your library. -generate_cover_title_font = None -generate_cover_foot_font = None - #: Fuzz value for trimming covers # The value used for the fuzz distance when trimming a cover. # Colors within this distance are considered equal. diff --git a/src/calibre/ebooks/__init__.py b/src/calibre/ebooks/__init__.py index d530d7dd65..024d48c886 100644 --- a/src/calibre/ebooks/__init__.py +++ b/src/calibre/ebooks/__init__.py @@ -8,8 +8,7 @@ from various formats. ''' import traceback, os, re -from cStringIO import StringIO -from calibre import CurrentDir, force_unicode +from calibre import CurrentDir class ConversionError(Exception): @@ -181,7 +180,6 @@ def normalize(x): def calibre_cover(title, author_string, series_string=None, output_format='jpg', title_size=46, author_size=36, logo_path=None): - from calibre.utils.config_base import tweaks title = normalize(title) author_string = normalize(author_string) series_string = normalize(series_string) @@ -189,9 +187,7 @@ def calibre_cover(title, author_string, series_string=None, import regex pat = regex.compile(ur'\p{Cf}+', flags=regex.VERSION1) # remove non-printing chars like the soft hyphen text = pat.sub(u'', title + author_string + (series_string or u'')) - font_path = tweaks['generate_cover_title_font'] - if font_path is None: - font_path = P('fonts/liberation/LiberationSerif-Bold.ttf') + font_path = P('fonts/liberation/LiberationSerif-Bold.ttf') from calibre.utils.fonts.utils import get_font_for_text font = open(font_path, 'rb').read() @@ -261,48 +257,8 @@ def unit_convert(value, base, font, dpi, body_font_size=12): def generate_masthead(title, output_path=None, width=600, height=60): from calibre.ebooks.conversion.config import load_defaults - from calibre.utils.config import tweaks - fp = tweaks['generate_cover_title_font'] - if not fp: - fp = P('fonts/liberation/LiberationSerif-Bold.ttf') - font_path = default_font = fp recs = load_defaults('mobi_output') - masthead_font_family = recs.get('masthead_font', 'Default') - - if masthead_font_family != 'Default': - from calibre.utils.fonts.scanner import font_scanner, NoFonts - try: - faces = font_scanner.fonts_for_family(masthead_font_family) - except NoFonts: - faces = [] - if faces: - font_path = faces[0]['path'] - - if not font_path or not os.access(font_path, os.R_OK): - font_path = default_font - - try: - from PIL import Image, ImageDraw, ImageFont - Image, ImageDraw, ImageFont - except ImportError: - import Image, ImageDraw, ImageFont - - img = Image.new('RGB', (width, height), 'white') - draw = ImageDraw.Draw(img) - try: - font = ImageFont.truetype(font_path, 48, encoding='unic') - except: - font = ImageFont.truetype(default_font, 48, encoding='unic') - text = force_unicode(title) - width, height = draw.textsize(text, font=font) - left = max(int((width - width)/2.), 0) - top = max(int((height - height)/2.), 0) - draw.text((left, top), text, fill=(0,0,0), font=font) - if output_path is None: - f = StringIO() - img.save(f, 'JPEG') - return f.getvalue() - else: - with open(output_path, 'wb') as f: - img.save(f, 'JPEG') + masthead_font_family = recs.get('masthead_font', None) + from calibre.ebooks.covers import generate_masthead + return generate_masthead(title, output_path=output_path, width=width, height=height, font_family=masthead_font_family) diff --git a/src/calibre/ebooks/covers.py b/src/calibre/ebooks/covers.py index c962eb5ef9..a1574a551e 100644 --- a/src/calibre/ebooks/covers.py +++ b/src/calibre/ebooks/covers.py @@ -19,7 +19,7 @@ from PyQt5.Qt import ( QPainterPath, QPen, QRectF ) -from calibre import force_unicode +from calibre import force_unicode, fit_image from calibre.constants import __appname__, __version__ from calibre.ebooks.metadata import fmt_sidx from calibre.ebooks.metadata.book.base import Metadata @@ -517,10 +517,76 @@ def create_cover(title, authors, series=None, series_index=1, prefs=None, as_qim prefs or cprefs, title_template=d['title_template'], subtitle_template=d['subtitle_template'], footer_template=d['footer_template']) return generate_cover(mi, prefs=prefs, as_qimage=as_qimage) +def calibre_cover2(title, author_string='', series_string='', prefs=None, as_qimage=False): + init_environment() + title, subtitle, footer = '' + escape_formatting(title), '' + escape_formatting(series_string), '' + escape_formatting(author_string) + prefs = prefs or cprefs + prefs = {k:prefs.get(k) for k in cprefs.defaults} + scale = 800. / prefs['cover_height'] + scale_cover(prefs, scale) + prefs = Prefs(**prefs) + img = QImage(prefs.cover_width, prefs.cover_height, QImage.Format_ARGB32) + img.fill(Qt.white) + # colors = to_theme('ffffff ffffff 000000 000000') + color_theme = theme_to_colors(fallback_colors) + class CalibeLogoStyle(Style): + NAME = GUI_NAME = 'calibre' + def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): + top = title_block.position.y + 10 + extra_spacing = subtitle_block.line_spacing // 2 if subtitle_block.line_spacing else title_block.line_spacing // 3 + height = title_block.height + subtitle_block.height + extra_spacing + title_block.leading + top += height + 25 + bottom = footer_block.position.y - 50 + logo = QImage(I('library.png')) + pwidth, pheight = rect.width(), bottom - top + scaled, width, height = fit_image(logo.width(), logo.height(), pwidth, pheight) + x, y = (pwidth - width) // 2, (pheight - height) // 2 + rect = QRect(x, top + y, width, height) + painter.setRenderHint(QPainter.SmoothPixmapTransform) + painter.drawImage(rect, logo) + return self.ccolor1, self.ccolor1, self.ccolor1 + style = CalibeLogoStyle(color_theme, prefs) + title_block, subtitle_block, footer_block = layout_text( + prefs, img, title, subtitle, footer, img.height() // 3, style) + p = QPainter(img) + rect = QRect(0, 0, img.width(), img.height()) + colors = style(p, rect, color_theme, title_block, subtitle_block, footer_block) + for block, color in zip((title_block, subtitle_block, footer_block), colors): + p.setPen(color) + block.draw(p) + p.end() + img.setText('Generated cover', '%s %s' % (__appname__, __version__)) + if as_qimage: + return img + return pixmap_to_data(img) + +def scale_cover(prefs, scale): + for x in ('cover_width', 'cover_height', 'title_font_size', 'subtitle_font_size', 'footer_font_size'): + prefs[x] = int(scale * prefs[x]) + +def generate_masthead(title, output_path=None, width=600, height=60, as_qimage=False, font_family=None): + init_environment() + font_family = font_family or cprefs['title_font_family'] or 'Liberation Serif' + img = QImage(width, height, QImage.Format_ARGB32) + img.fill(Qt.white) + p = QPainter(img) + f = QFont(font_family) + f.setPixelSize((height * 3) // 4), f.setBold(True) + p.setFont(f) + p.drawText(img.rect(), Qt.AlignLeft | Qt.AlignVCenter, sanitize(title)) + p.end() + if as_qimage: + return img + data = pixmap_to_data(img) + if output_path is None: + return data + with open(output_path, 'wb') as f: + f.write(data) + def test(scale=0.25): from PyQt5.Qt import QLabel, QApplication, QPixmap, QMainWindow, QWidget, QScrollArea, QGridLayout app = QApplication([]) - mi = Metadata('xxx', ['Kovid Goyal', 'John Q. Doe', 'Author']) + mi = Metadata('xxx', ['Kovid Goyal', 'John & Doe', 'Author']) mi.series = 'A series of styles' m = QMainWindow() sa = QScrollArea(m) @@ -534,8 +600,7 @@ def test(scale=0.25): mi.series_index = c + 1 mi.title = 'An algorithmic cover [%s]' % color prefs = override_prefs(cprefs, override_color_theme=color, override_style=style) - for x in ('cover_width', 'cover_height', 'title_font_size', 'subtitle_font_size', 'footer_font_size'): - prefs[x] = int(scale * prefs[x]) + scale_cover(prefs, scale) img = generate_cover(mi, prefs=prefs, as_qimage=True) la = QLabel() la.setPixmap(QPixmap.fromImage(img)) diff --git a/src/calibre/library/catalogs/epub_mobi.py b/src/calibre/library/catalogs/epub_mobi.py index 0b31a6c773..8006d53531 100644 --- a/src/calibre/library/catalogs/epub_mobi.py +++ b/src/calibre/library/catalogs/epub_mobi.py @@ -13,7 +13,6 @@ from collections import namedtuple from calibre import strftime from calibre.customize import CatalogPlugin from calibre.customize.conversion import OptionRecommendation, DummyReporter -from calibre.ebooks import calibre_cover from calibre.library import current_library_name from calibre.library.catalogs import AuthorSortMismatchException, EmptyCatalogException from calibre.ptempfile import PersistentTemporaryFile @@ -463,9 +462,10 @@ class EPUB_MOBI(CatalogPlugin): recommendations.append(('cover', cpath, OptionRecommendation.HIGH)) log.info("using existing catalog cover") else: + from calibre.ebooks.covers import calibre_cover2 log.info("replacing catalog cover") new_cover_path = PersistentTemporaryFile(suffix='.jpg') - new_cover = calibre_cover(opts.catalog_title.replace('"', '\\"'), 'calibre') + new_cover = calibre_cover2(opts.catalog_title, 'calibre') new_cover_path.write(new_cover) new_cover_path.close() recommendations.append(('cover', new_cover_path.name, OptionRecommendation.HIGH)) diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index 0a628d565c..6e093c45d8 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -273,9 +273,7 @@ def create_cover_page(top_lines, logo_path, width=590, height=750, bottom += line.bottom_margin bottom -= top_lines[-1].bottom_margin - foot_font = tweaks['generate_cover_foot_font'] - if not foot_font: - foot_font = P('fonts/liberation/LiberationMono-Regular.ttf') + foot_font = P('fonts/liberation/LiberationMono-Regular.ttf') vanity = create_text_arc(__appname__ + ' ' + __version__, 24, font=foot_font, bgcolor='#00000000') lwidth, lheight = vanity.size