diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index 4bb8fff2f9..6cb351898b 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -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)
diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui
index 5da9d37d04..07f5764028 100644
--- a/src/calibre/gui2/dialogs/metadata_single.ui
+++ b/src/calibre/gui2/dialogs/metadata_single.ui
@@ -653,6 +653,13 @@
+ -
+
+
+ &Generate cover
+
+
+
@@ -736,15 +743,17 @@
fetch_metadata_button
add_format_button
remove_format_button
+ button_set_cover
+ button_set_metadata
+ formats
cover_path
cover_button
reset_cover
fetch_cover_button
- button_set_cover
- formats
- button_set_metadata
- button_box
+ generate_cover_button
scrollArea
+ central_widget
+ button_box
diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py
index 766a0ad861..b0f75b4ecd 100644
--- a/src/calibre/utils/magick/draw.py
+++ b/src/calibre/utils/magick/draw.py
@@ -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)