A nice class for easily creating collages

This commit is contained in:
Kovid Goyal 2016-05-04 20:35:26 +05:30
parent 929e50404e
commit 768b8ba990
2 changed files with 42 additions and 25 deletions

View File

@ -17,7 +17,7 @@ from PyQt5.Qt import (
QLineEdit, QSpinBox, QTextEdit, QSize, QListWidgetItem, QIcon, QImage, QLineEdit, QSpinBox, QTextEdit, QSize, QListWidgetItem, QIcon, QImage,
pyqtSignal, QStackedLayout, QWidget, QLabel, Qt, QComboBox, QPixmap, pyqtSignal, QStackedLayout, QWidget, QLabel, Qt, QComboBox, QPixmap,
QGridLayout, QStyledItemDelegate, QModelIndex, QApplication, QStaticText, QGridLayout, QStyledItemDelegate, QModelIndex, QApplication, QStaticText,
QStyle, QPen, QColor, QPainter QStyle, QPen
) )
from calibre import walk, fit_image, human_readable from calibre import walk, fit_image, human_readable
@ -31,7 +31,7 @@ from calibre.utils.date import utcnow
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
from calibre.utils.https import get_https_resource_securely, HTTPError from calibre.utils.https import get_https_resource_securely, HTTPError
from calibre.utils.icu import numeric_sort_key as sort_key from calibre.utils.icu import numeric_sort_key as sort_key
from calibre.utils.img import image_from_data, image_to_data from calibre.utils.img import image_from_data, Canvas
from calibre.utils.zipfile import ZipFile, ZIP_STORED from calibre.utils.zipfile import ZipFile, ZIP_STORED
from calibre.utils.filenames import atomic_rename from calibre.utils.filenames import atomic_rename
from lzma.xz import compress, decompress from lzma.xz import compress, decompress
@ -153,29 +153,26 @@ def default_cover_icons(cols=5):
def create_cover(report, icons=(), cols=5, size=60, padding=8): def create_cover(report, icons=(), cols=5, size=60, padding=8):
icons = icons or tuple(default_cover_icons(cols)) icons = icons or tuple(default_cover_icons(cols))
rows = int(math.ceil(len(icons) / cols)) rows = int(math.ceil(len(icons) / cols))
canvas = QImage(cols * (size + padding), rows * (size + padding), QImage.Format_RGB32) with Canvas(cols * (size + padding), rows * (size + padding), bgcolor='#eee') as canvas:
canvas.fill(QColor('#eeeeee')) y = -size - padding // 2
p = QPainter(canvas) x = 0
y = -size - padding // 2 for i, icon in enumerate(icons):
x = 0 if i % cols == 0:
for i, icon in enumerate(icons): y += padding + size
if i % cols == 0: x = padding // 2
y += padding + size else:
x = padding // 2 x += size + padding
else: if report and icon in report.name_map:
x += size + padding ipath = os.path.join(report.path, report.name_map[icon])
if report and icon in report.name_map: else:
ipath = os.path.join(report.path, report.name_map[icon]) ipath = I(icon, allow_user_override=False)
else: with lopen(ipath, 'rb') as f:
ipath = I(icon, allow_user_override=False) img = image_from_data(f.read())
with lopen(ipath, 'rb') as f: scaled, nwidth, nheight = fit_image(img.width(), img.height(), size, size)
img = image_from_data(f.read()) img = img.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
scaled, nwidth, nheight = fit_image(img.width(), img.height(), size, size) dx = (size - nwidth) // 2
img = img.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) canvas.compose(img, x + dx, y)
dx = (size - nwidth) // 2 return canvas.export()
p.drawImage(x + dx, y, img)
p.end()
return image_to_data(canvas)
def verify_theme(report): def verify_theme(report):
must_use_qt() must_use_qt()

View File

@ -168,6 +168,26 @@ def blend_on_canvas(img, width, height, bgcolor='#ffffff'):
p.end() p.end()
return nimg return nimg
class Canvas(object):
def __init__(self, width, height, bgcolor='#ffffff'):
self.img = QImage(width, height, QImage.Format_RGB32)
self.img.fill(QColor(bgcolor))
def __enter__(self):
self.painter = QPainter(self.img)
return self
def __exit__(self, *args):
self.painter.end()
def compose(self, img, x=0, y=0):
img = image_from_data(img)
self.painter.drawImage(x, y, img)
def export(self, fmt='JPEG', compression_quality=95):
return image_to_data(self.img, compression_quality=compression_quality, fmt=fmt)
def run_optimizer(file_path, cmd, as_filter=False, input_data=None): def run_optimizer(file_path, cmd, as_filter=False, input_data=None):
file_path = os.path.abspath(file_path) file_path = os.path.abspath(file_path)
cwd = os.path.dirname(file_path) cwd = os.path.dirname(file_path)