Refactor scale_img into its own module

This commit is contained in:
Kovid Goyal 2015-11-13 21:51:32 +05:30
parent 30bcd2ab8f
commit 7905e70cdf
2 changed files with 53 additions and 26 deletions

View File

@ -11,8 +11,6 @@ from binascii import hexlify
from io import BytesIO from io import BytesIO
from threading import Lock from threading import Lock
from PyQt5.Qt import QImage, QByteArray, QBuffer, Qt
from calibre import fit_image from calibre import fit_image
from calibre.constants import config_dir, iswindows from calibre.constants import config_dir, iswindows
from calibre.db.errors import NoSuchFormat from calibre.db.errors import NoSuchFormat
@ -25,6 +23,7 @@ from calibre.srv.routes import endpoint, json
from calibre.srv.utils import http_date from calibre.srv.utils import http_date
from calibre.utils.config_base import tweaks from calibre.utils.config_base import tweaks
from calibre.utils.date import timestampfromdt from calibre.utils.date import timestampfromdt
from calibre.utils.img import scale_image, image_from_data
from calibre.utils.filenames import ascii_filename, atomic_rename from calibre.utils.filenames import ascii_filename, atomic_rename
from calibre.utils.shared_file import share_open from calibre.utils.shared_file import share_open
@ -94,28 +93,6 @@ def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func
rd.outheaders['Tempfile'] = hexlify(fname.encode('utf-8')) rd.outheaders['Tempfile'] = hexlify(fname.encode('utf-8'))
return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data) return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
def scale_image(data, width=60, height=80, compression_quality=75, as_png=False):
# We use Qt instead of ImageMagick here because ImageMagick seems to use
# some kind of memory pool, causing memory consumption in the server to
# sky rocket. Since we are only using QImage this method is thread safe,
# and does not require a QApplication
if isinstance(data, QImage):
img = data
else:
img = QImage()
if not img.loadFromData(data):
raise ValueError('Could not load image for thumbnail generation')
scaled, nwidth, nheight = fit_image(img.width(), img.height(), width, height)
if scaled:
img = img.scaled(nwidth, nheight, Qt.KeepAspectRatio, Qt.SmoothTransformation)
ba = QByteArray()
buf = QBuffer(ba)
buf.open(QBuffer.WriteOnly)
fmt = 'PNG' if as_png else 'JPEG'
if not img.save(buf, fmt, quality=compression_quality):
raise ValueError('Failed to export thumbnail image to: ' + fmt)
return ba.data()
def cover(ctx, rd, library_id, db, book_id, width=None, height=None): def cover(ctx, rd, library_id, db, book_id, width=None, height=None):
mtime = db.cover_last_modified(book_id) mtime = db.cover_last_modified(book_id)
if mtime is None: if mtime is None:
@ -231,9 +208,8 @@ def icon(ctx, rd, which):
except EnvironmentError: except EnvironmentError:
raise HTTPNotFound() raise HTTPNotFound()
with src: with src:
img = QImage()
idata = src.read() idata = src.read()
img.loadFromData(idata) img = image_from_data(idata)
scaled, width, height = fit_image(img.width(), img.height(), sz, sz) scaled, width, height = fit_image(img.width(), img.height(), sz, sz)
if scaled: if scaled:
idata = scale_image(img, width, height, as_png=True) idata = scale_image(img, width, height, as_png=True)

51
src/calibre/utils/img.py Normal file
View File

@ -0,0 +1,51 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import (unicode_literals, division, absolute_import,
print_function)
from PyQt5.Qt import QImage, QByteArray, QBuffer, Qt, QPainter
from calibre import fit_image
def image_from_data(data):
i = QImage()
if not i.loadFromData(data):
raise ValueError('Not a valid image')
return i
def scale_image(data, width=60, height=80, compression_quality=70, as_png=False, preserve_aspect_ratio=True):
# We use Qt instead of ImageMagick here because ImageMagick seems to use
# some kind of memory pool, causing memory consumption to sky rocket. Since
# we are only using QImage this method is thread safe, and does not require
# a QApplication/GUI thread
if isinstance(data, QImage):
img = data
else:
img = QImage()
if not img.loadFromData(data):
raise ValueError('Could not load image for thumbnail generation')
if preserve_aspect_ratio:
scaled, nwidth, nheight = fit_image(img.width(), img.height(), width, height)
if scaled:
img = img.scaled(nwidth, nheight, Qt.KeepAspectRatio, Qt.SmoothTransformation)
else:
if img.width() != width or img.height() != height:
img = img.scaled(width, height, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
if not as_png and img.hasAlphaChannel():
nimg = QImage(img.size(), QImage.Format_RGB32)
nimg.fill(Qt.white)
p = QPainter(nimg)
p.drawImage(0, 0, img)
p.end()
img = nimg
ba = QByteArray()
buf = QBuffer(ba)
buf.open(QBuffer.WriteOnly)
fmt = 'PNG' if as_png else 'JPEG'
if not img.save(buf, fmt, quality=compression_quality):
raise ValueError('Failed to export thumbnail image to: ' + fmt)
return ba.data()