A banner based style for auto generated covers

This commit is contained in:
Kovid Goyal 2014-09-13 15:24:57 +05:30
parent e22c980fc1
commit 5c80c68a43

View File

@ -9,13 +9,14 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
import re, random import re, random
from collections import namedtuple from collections import namedtuple
from contextlib import contextmanager from contextlib import contextmanager
from math import ceil from math import ceil, sqrt, cos, sin, atan2
from future_builtins import map, zip from future_builtins import map, zip
from itertools import chain, repeat from itertools import chain, repeat
from PyQt5.Qt import ( from PyQt5.Qt import (
QImage, Qt, QFont, QPainter, QPointF, QTextLayout, QTextOption, QImage, Qt, QFont, QPainter, QPointF, QTextLayout, QTextOption,
QFontMetrics, QTextCharFormat, QColor, QRect, QBrush, QLinearGradient QFontMetrics, QTextCharFormat, QColor, QRect, QBrush, QLinearGradient,
QPainterPath, QPen
) )
from calibre import force_unicode from calibre import force_unicode
@ -189,7 +190,7 @@ def layout_text(prefs, img, title, subtitle, footer, max_height, style):
gap = 2 * title_block.leading gap = 2 * title_block.leading
mh = max_height - title_block.height - gap mh = max_height - title_block.height - gap
subtitle_block = Block(subtitle, width, subtitle_font, img, mh, style.SUBTITLE_ALIGN) subtitle_block = Block(subtitle, width, subtitle_font, img, mh, style.SUBTITLE_ALIGN)
subtitle_block.position = style.hmargin, title_block.position[0] + title_block.height + gap subtitle_block.position = style.hmargin, title_block.position.y + title_block.height + gap
footer_font = QFont(prefs.footer_font_family) footer_font = QFont(prefs.footer_font_family)
footer_font.setPixelSize(prefs.footer_font_size) footer_font.setPixelSize(prefs.footer_font_size)
@ -282,8 +283,8 @@ class Style(object):
self.calculate_margins(prefs) self.calculate_margins(prefs)
def calculate_margins(self, prefs): def calculate_margins(self, prefs):
self.hmargin = (50 / 600) * prefs.cover_width self.hmargin = int((50 / 600) * prefs.cover_width)
self.vmargin = (50 / 800) * prefs.cover_height self.vmargin = int((50 / 800) * prefs.cover_height)
def load_colors(self, color_theme): def load_colors(self, color_theme):
self.color1 = color(color_theme, 'color1', Qt.white) self.color1 = color(color_theme, 'color1', Qt.white)
@ -315,14 +316,84 @@ class Half(Style):
painter.fillRect(rect, QBrush(g)) painter.fillRect(rect, QBrush(g))
return self.ccolor1, self.ccolor1, self.ccolor1 return self.ccolor1, self.ccolor1, self.ccolor1
# class Ribbon(Style): def rotate_vector(angle, x, y):
# return x * cos(angle) - y * sin(angle), x * sin(angle) + y * cos(angle)
# NAME = 'Ribbon'
# GUI_NAME = _('Ribbon') def draw_curved_line(painter_path, dx, dy, c1_frac, c1_amp, c2_frac, c2_amp):
# length = sqrt(dx * dx + dy * dy)
# def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): angle = atan2(dy, dx)
# top = title_block.position.y c1 = QPointF(*rotate_vector(angle, c1_frac * length, c1_amp * length))
# height = title_block.height + subtitle_block.height + title_block.line_spacing // 3 c2 = QPointF(*rotate_vector(angle, c2_frac * length, c2_amp * length))
pos = painter_path.currentPosition()
painter_path.cubicTo(pos + c1, pos + c2, pos + QPointF(dx, dy))
class Banner(Style):
NAME = 'Banner'
GUI_NAME = _('Banner')
GRADE = 0.07
def calculate_margins(self, prefs):
Style.calculate_margins(self, prefs)
self.hmargin = int(0.15 * prefs.cover_width)
self.fold_width = int(0.1 * prefs.cover_width)
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
painter.fillRect(rect, self.color1)
top = title_block.position.y + 10
height = title_block.height + subtitle_block.height + title_block.line_spacing // 2
right = rect.right() - self.hmargin
width = right - self.hmargin
# Draw main banner
p = main = QPainterPath(QPointF(self.hmargin, top))
draw_curved_line(p, rect.width() - 2 * self.hmargin, 0, 0.1, -0.1, 0.9, -0.1)
deltax = self.GRADE * height
p.lineTo(right + deltax, top + height)
right_corner = p.currentPosition()
draw_curved_line(p, - width - 2 * deltax, 0, 0.1, 0.05, 0.9, 0.05)
left_corner = p.currentPosition()
p.closeSubpath()
# Draw fold rectangles
rwidth = self.fold_width
yfrac = 0.1
width23 = int(0.67 * rwidth)
rtop = top + height * yfrac
def draw_fold(x, m=1, corner=left_corner):
ans = p = QPainterPath(QPointF(x, rtop))
draw_curved_line(p, rwidth*m, 0, 0.1, 0.1*m, 0.5, -0.2*m)
fold_upper = p.currentPosition()
p.lineTo(p.currentPosition() + QPointF(-deltax*m, height))
fold_corner = p.currentPosition()
draw_curved_line(p, -rwidth*m, 0, 0.2, -0.1*m, 0.8, -0.1*m)
draw_curved_line(p, deltax*m, -height, 0.2, 0.1*m, 0.8, 0.1*m)
p = inner_fold = QPainterPath(corner)
dp = fold_corner - p.currentPosition()
draw_curved_line(p, dp.x(), dp.y(), 0.5, 0.3*m, 1, 0*m)
p.lineTo(fold_upper), p.closeSubpath()
return ans, inner_fold
left_fold, left_inner = draw_fold(self.hmargin - width23)
right_fold, right_inner = draw_fold(right + width23, m=-1, corner=right_corner)
painter.save()
painter.setRenderHint(QPainter.Antialiasing)
pen = QPen(self.ccolor2)
pen.setWidth(3)
pen.setJoinStyle(Qt.RoundJoin)
painter.setPen(pen)
for r in (left_fold, right_fold):
painter.fillPath(r, QBrush(self.color2))
painter.drawPath(r)
for r in (left_inner, right_inner):
painter.fillPath(r, QBrush(self.color2.darker()))
painter.drawPath(r)
painter.fillPath(main, QBrush(self.color2))
painter.drawPath(main)
painter.restore()
return self.ccolor2, self.ccolor2, self.ccolor1
class Blocks(Style): class Blocks(Style):