mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement #5959 (generate default cover on request)
This commit is contained in:
parent
cb809e74a8
commit
9aa0fc428d
@ -142,6 +142,21 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.cpixmap = pix
|
||||
self.cover_data = cover
|
||||
|
||||
def generate_cover(self, *args):
|
||||
from calibre.utils.magick.draw import create_cover_page, TextLine
|
||||
title = unicode(self.title.text()).strip()
|
||||
author = unicode(self.authors.text()).strip()
|
||||
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)
|
||||
lines = [TextLine(title, 44), TextLine(author, 32)]
|
||||
self.cover_data = create_cover_page(lines, I('library.png'))
|
||||
pix = QPixmap()
|
||||
pix.loadFromData(self.cover_data)
|
||||
self.cover.setPixmap(pix)
|
||||
self.cover_changed = True
|
||||
self.cpixmap = pix
|
||||
|
||||
def add_format(self, x):
|
||||
files = choose_files(self, 'add formats dialog',
|
||||
@ -425,6 +440,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.central_widget.tabBar().setVisible(False)
|
||||
else:
|
||||
self.create_custom_column_editors()
|
||||
self.generate_cover_button.clicked.connect(self.generate_cover)
|
||||
|
||||
def create_custom_column_editors(self):
|
||||
w = self.central_widget.widget(1)
|
||||
|
@ -653,6 +653,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="generate_cover_button">
|
||||
<property name="text">
|
||||
<string>&Generate cover</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@ -736,15 +743,17 @@
|
||||
<tabstop>fetch_metadata_button</tabstop>
|
||||
<tabstop>add_format_button</tabstop>
|
||||
<tabstop>remove_format_button</tabstop>
|
||||
<tabstop>button_set_cover</tabstop>
|
||||
<tabstop>button_set_metadata</tabstop>
|
||||
<tabstop>formats</tabstop>
|
||||
<tabstop>cover_path</tabstop>
|
||||
<tabstop>cover_button</tabstop>
|
||||
<tabstop>reset_cover</tabstop>
|
||||
<tabstop>fetch_cover_button</tabstop>
|
||||
<tabstop>button_set_cover</tabstop>
|
||||
<tabstop>formats</tabstop>
|
||||
<tabstop>button_set_metadata</tabstop>
|
||||
<tabstop>button_box</tabstop>
|
||||
<tabstop>generate_cover_button</tabstop>
|
||||
<tabstop>scrollArea</tabstop>
|
||||
<tabstop>central_widget</tabstop>
|
||||
<tabstop>button_box</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../../../resources/images.qrc"/>
|
||||
|
@ -7,6 +7,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from calibre.utils.magick import Image, DrawingWand, create_canvas
|
||||
from calibre.constants import __appname__, __version__
|
||||
|
||||
def save_cover_data_to(data, path, bgcolor='white', resize_to=None):
|
||||
'''
|
||||
@ -77,4 +78,87 @@ def create_text_arc(text, font_size, font=None, bgcolor='white'):
|
||||
canvas.trim(0)
|
||||
return canvas
|
||||
|
||||
def _get_line(img, dw, tokens, line_width):
|
||||
line, rest = tokens, []
|
||||
while True:
|
||||
m = img.font_metrics(dw, ' '.join(line))
|
||||
width, height = m.text_width, m.text_height
|
||||
if width < line_width:
|
||||
return line, rest
|
||||
rest = line[-1:] + rest
|
||||
line = line[:-1]
|
||||
|
||||
def annotate_img(img, dw, left, top, rotate, text,
|
||||
translate_from_top_left=True):
|
||||
if isinstance(text, unicode):
|
||||
text = text.encode('utf-8')
|
||||
if translate_from_top_left:
|
||||
m = img.font_metrics(dw, text)
|
||||
img_width, img_height = img.size
|
||||
left = left - img_width/2. + m.text_width/2.
|
||||
top = top - img_height/2. + m.text_height/2.
|
||||
img.annotate(dw, left, top, rotate, text)
|
||||
|
||||
def draw_centered_line(img, dw, line, top):
|
||||
m = img.font_metrics(dw, line)
|
||||
width, height = m.text_width, m.text_height
|
||||
img_width = img.size[0]
|
||||
left = max(int((img_width - width)/2.), 0)
|
||||
annotate_img(img, dw, left, top, 0, line)
|
||||
return top + height
|
||||
|
||||
def draw_centered_text(img, dw, text, top, margin=10):
|
||||
img_width = img.size[0]
|
||||
tokens = text.split(' ')
|
||||
while tokens:
|
||||
line, tokens = _get_line(img, dw, tokens, img_width-2*margin)
|
||||
if not line:
|
||||
# Could not fit the first token on the line
|
||||
line = tokens[:1]
|
||||
tokens = tokens[1:]
|
||||
bottom = draw_centered_line(img, dw, ' '.join(line), top)
|
||||
top = bottom
|
||||
return top
|
||||
|
||||
class TextLine(object):
|
||||
|
||||
def __init__(self, text, font_size, bottom_margin=30, font_path=None):
|
||||
self.text, self.font_size, = text, font_size
|
||||
self.bottom_margin = bottom_margin
|
||||
self.font_path = font_path
|
||||
|
||||
def __repr__(self):
|
||||
return u'TextLine:%r:%f'%(self.text, self.font_size)
|
||||
|
||||
|
||||
def create_cover_page(top_lines, logo_path, width=590, height=750,
|
||||
bgcolor='white', output_format='jpg'):
|
||||
'''
|
||||
Create the standard calibre cover page and return it as a byte string in
|
||||
the specified output_format.
|
||||
'''
|
||||
canvas = create_canvas(width, height, bgcolor)
|
||||
|
||||
bottom = 10
|
||||
for line in top_lines:
|
||||
twand = create_text_wand(line.font_size, font_path=line.font_path)
|
||||
bottom = draw_centered_text(canvas, twand, line.text, bottom)
|
||||
bottom += line.bottom_margin
|
||||
bottom -= top_lines[-1].bottom_margin
|
||||
|
||||
vanity = create_text_arc(__appname__ + ' ' + __version__, 24,
|
||||
font=P('fonts/liberation/LiberationMono-Regular.ttf'))
|
||||
lwidth, lheight = vanity.size
|
||||
left = int(max(0, (width - lwidth)/2.))
|
||||
top = height - lheight - 10
|
||||
canvas.compose(vanity, left, top)
|
||||
|
||||
logo = Image()
|
||||
logo.open(logo_path)
|
||||
lwidth, lheight = logo.size
|
||||
left = int(max(0, (width - lwidth)/2.))
|
||||
top = max(int((height - lheight)/2.), bottom+20)
|
||||
canvas.compose(logo, left, top)
|
||||
|
||||
return canvas.export(output_format)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user