mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Some optimizations for previous PR
1) Set device pixel ratio on generated QPixmap 2) Avoid copying image data when loading cover from library 3) Convert thumbnail to RGBA in cover thread so as to do less work in GUI thread
This commit is contained in:
parent
dbc4860ac5
commit
f97147afec
@ -1708,7 +1708,7 @@ class DB:
|
||||
return True
|
||||
return False
|
||||
|
||||
def cover_or_cache(self, path, timestamp):
|
||||
def cover_or_cache(self, path, timestamp, as_what='bytes'):
|
||||
path = os.path.abspath(os.path.join(self.library_path, path, COVER_FILE_NAME))
|
||||
try:
|
||||
stat = os.stat(path)
|
||||
@ -1723,7 +1723,13 @@ class DB:
|
||||
time.sleep(0.2)
|
||||
f = open(path, 'rb')
|
||||
with f:
|
||||
return True, f.read(), stat.st_mtime
|
||||
if as_what == 'pil_image':
|
||||
from PIL import Image
|
||||
data = Image.open(f)
|
||||
data.load()
|
||||
else:
|
||||
data = f.read()
|
||||
return True, data, stat.st_mtime
|
||||
|
||||
def compress_covers(self, path_map, jpeg_quality, progress_callback):
|
||||
cpath_map = {}
|
||||
|
@ -1161,12 +1161,12 @@ class Cache:
|
||||
return ret
|
||||
|
||||
@read_api
|
||||
def cover_or_cache(self, book_id, timestamp):
|
||||
def cover_or_cache(self, book_id, timestamp, as_what='bytes'):
|
||||
try:
|
||||
path = self._field_for('path', book_id).replace('/', os.sep)
|
||||
except AttributeError:
|
||||
return False, None, None
|
||||
return self.backend.cover_or_cache(path, timestamp)
|
||||
return self.backend.cover_or_cache(path, timestamp, as_what)
|
||||
|
||||
@read_api
|
||||
def cover_last_modified(self, book_id):
|
||||
|
@ -777,10 +777,7 @@ class GridView(QListView):
|
||||
|
||||
@property
|
||||
def device_pixel_ratio(self):
|
||||
try:
|
||||
return self.devicePixelRatioF()
|
||||
except AttributeError:
|
||||
return self.devicePixelRatio()
|
||||
return self.devicePixelRatioF()
|
||||
|
||||
@property
|
||||
def first_visible_row(self):
|
||||
@ -964,17 +961,16 @@ class GridView(QListView):
|
||||
cdata, timestamp = tc[book_id] # None, None if not cached.
|
||||
if timestamp is None:
|
||||
# Cover not in cache. Try to read the cover from the library.
|
||||
has_cover, cdata, timestamp = db.new_api.cover_or_cache(book_id, 0)
|
||||
has_cover, cdata, timestamp = db.new_api.cover_or_cache(book_id, 0, as_what='pil_image')
|
||||
if has_cover:
|
||||
# There is a cover.jpg. Convert the byte string to an image.
|
||||
cache_valid = False
|
||||
cdata = Image.open(BytesIO(cdata))
|
||||
else:
|
||||
# No cover.jpg
|
||||
cache_valid = None
|
||||
else:
|
||||
# A cover is in the cache. Check whether it is up to date.
|
||||
has_cover, tcdata, timestamp = db.new_api.cover_or_cache(book_id, timestamp)
|
||||
has_cover, tcdata, timestamp = db.new_api.cover_or_cache(book_id, timestamp, as_what='pil_image')
|
||||
if has_cover:
|
||||
if tcdata is None:
|
||||
# The cached cover is up-to-date.
|
||||
@ -983,9 +979,6 @@ class GridView(QListView):
|
||||
else:
|
||||
# The cached cover is stale
|
||||
cache_valid = False
|
||||
# Convert the bytes from the cover.jpg. The image will be
|
||||
# resized later.
|
||||
cdata = Image.open(BytesIO(tcdata))
|
||||
else:
|
||||
# We found a cached cover for a book without a cover. This can
|
||||
# happen in older version of calibre that can reuse book_ids
|
||||
@ -1067,6 +1060,10 @@ class GridView(QListView):
|
||||
# Return the thumbnail, which is either None or a PIL Image. If not None
|
||||
# the image will be converted to a QPixmap on the GUI thread. Putting
|
||||
# None into the CoverCache ensures re-rendering won't try again.
|
||||
if getattr(thumb, 'mode', None) == 'RGB':
|
||||
# Conversion to QPixmap needs RGBA data so do it here rather than
|
||||
# in the GUI thread
|
||||
thumb = thumb.convert('RGBA')
|
||||
return thumb
|
||||
|
||||
def re_render(self, book_id, thumb):
|
||||
@ -1076,7 +1073,7 @@ class GridView(QListView):
|
||||
self.delegate.cover_cache.clear_staging()
|
||||
if thumb is not None:
|
||||
# Convert the image to a QPixmap
|
||||
thumb = convert_PIL_image_to_pixmap(thumb)
|
||||
thumb = convert_PIL_image_to_pixmap(thumb, self.device_pixel_ratio)
|
||||
self.delegate.cover_cache.set(book_id, thumb)
|
||||
m = self.model()
|
||||
try:
|
||||
|
@ -688,10 +688,16 @@ def align8to32(bytes, width, mode):
|
||||
return b"".join(new_data)
|
||||
|
||||
|
||||
def convert_PIL_image_to_pixmap(im):
|
||||
def convert_PIL_image_to_pixmap(im, device_pixel_ratio=1.0):
|
||||
data = None
|
||||
colortable = None
|
||||
if im.mode == "1":
|
||||
if im.mode == "RGBA":
|
||||
fmt = QImage.Format.Format_RGBA8888
|
||||
data = im.tobytes("raw", "RGBA")
|
||||
elif im.mode == "RGB":
|
||||
fmt = QImage.Format.Format_RGBX8888
|
||||
data = im.convert("RGBA").tobytes("raw", "RGBA")
|
||||
elif im.mode == "1":
|
||||
fmt = QImage.Format.Format_Mono
|
||||
elif im.mode == "L":
|
||||
fmt = QImage.Format.Format_Indexed8
|
||||
@ -700,12 +706,6 @@ def convert_PIL_image_to_pixmap(im):
|
||||
fmt = QImage.Format.Format_Indexed8
|
||||
palette = im.getpalette()
|
||||
colortable = [qRgba(*palette[i : i + 3], 255) & 0xFFFFFFFF for i in range(0, len(palette), 3)]
|
||||
elif im.mode == "RGB":
|
||||
fmt = QImage.Format.Format_RGBX8888
|
||||
data = im.convert("RGBA").tobytes("raw", "RGBA")
|
||||
elif im.mode == "RGBA":
|
||||
fmt = QImage.Format.Format_RGBA8888
|
||||
data = im.tobytes("raw", "RGBA")
|
||||
elif im.mode == "I;16":
|
||||
im = im.point(lambda i: i * 256)
|
||||
fmt = QImage.Format.Format_Grayscale16
|
||||
@ -715,6 +715,8 @@ def convert_PIL_image_to_pixmap(im):
|
||||
size = im.size
|
||||
data = data or align8to32(im.tobytes(), size[0], im.mode)
|
||||
qimg = QImage(data, size[0], size[1], fmt)
|
||||
if device_pixel_ratio != 1.0:
|
||||
qimg.setDevicePixelRatio(device_pixel_ratio)
|
||||
if colortable:
|
||||
qimg.setColorTable(colortable)
|
||||
return QPixmap.fromImage(qimg)
|
||||
|
Loading…
x
Reference in New Issue
Block a user