mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Use Qt to draw catalog covers and mastheads as well
This commit is contained in:
parent
9963e4263e
commit
88df6cbb3d
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 = '<b>' + escape_formatting(title), '<i>' + escape_formatting(series_string), '<b>' + 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))
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user