Edit book: Fix compress images losslessly failing for a few images on windows when there are a lot of images in the book. Fixes #1877066 [Error in Compressing images losslessly](https://bugs.launchpad.net/calibre/+bug/1877066)

This commit is contained in:
Kovid Goyal 2020-05-10 11:01:04 +05:30
parent b76b0a6c53
commit 319f289851
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -16,9 +16,9 @@ class Worker(Thread):
daemon = True
def __init__(self, abort, name, queue, results, container, jpeg_quality, progress_callback):
def __init__(self, abort, name, queue, results, jpeg_quality, progress_callback):
Thread.__init__(self, name=name)
self.queue, self.results, self.container = queue, results, container
self.queue, self.results = queue, results
self.progress_callback = progress_callback
self.jpeg_quality = jpeg_quality
self.abort = abort
@ -27,11 +27,11 @@ class Worker(Thread):
def run(self):
while not self.abort.is_set():
try:
name = self.queue.get_nowait()
name, path, mt = self.queue.get_nowait()
except Empty:
break
try:
self.compress(name)
self.compress(name, path, mt)
except Exception:
import traceback
self.results[name] = (False, traceback.format_exc())
@ -43,16 +43,14 @@ class Worker(Thread):
traceback.print_exc()
self.queue.task_done()
def compress(self, name):
def compress(self, name, path, mime_type):
from calibre.utils.img import optimize_png, optimize_jpeg, encode_jpeg
mt = self.container.mime_map[name]
if 'png' in mt:
if 'png' in mime_type:
func = optimize_png
elif self.jpeg_quality is None:
func = optimize_jpeg
else:
func = partial(encode_jpeg, quality=self.jpeg_quality)
path = self.container.get_file_path_for_processing(name)
before = os.path.getsize(path)
with lopen(path, 'rb') as f:
old_data = f.read()
@ -80,17 +78,24 @@ def compress_images(container, report=None, names=None, jpeg_quality=None, progr
results = {}
queue = Queue()
abort = Event()
for name in images:
queue.put(name)
seen = set()
num_to_process = 0
for name in sorted(images):
path = os.path.normcase(os.path.abspath(container.get_file_path_for_processing(name)))
if path not in seen:
num_to_process += 1
queue.put((name, path, container.mime_map[name]))
seen.add(path)
def pc(name):
keep_going = progress_callback(len(results), len(images), name)
keep_going = progress_callback(len(results), num_to_process, name)
if not keep_going:
abort.set()
progress_callback(0, len(images), '')
[Worker(abort, 'CompressImage%d' % i, queue, results, container, jpeg_quality, pc) for i in range(min(detect_ncpus(), len(images)))]
progress_callback(0, num_to_process, '')
[Worker(abort, 'CompressImage%d' % i, queue, results, jpeg_quality, pc) for i in range(min(detect_ncpus(), num_to_process))]
queue.join()
before_total = after_total = 0
processed_num = 0
changed = False
for name, (ok, res) in iteritems(results):
name = force_unicode(name, filesystem_encoding)
@ -98,6 +103,7 @@ def compress_images(container, report=None, names=None, jpeg_quality=None, progr
before, after = res
if before != after:
changed = True
processed_num += 1
before_total += before
after_total += after
if report:
@ -112,8 +118,8 @@ def compress_images(container, report=None, names=None, jpeg_quality=None, progr
if report:
if changed:
report('')
report(_('Total image filesize reduced from {0} to {1} [{2:.1%} reduction]').format(
human_readable(before_total), human_readable(after_total), (before_total - after_total)/before_total))
report(_('Total image filesize reduced from {0} to {1} [{2:.1%} reduction, {3} images changed]').format(
human_readable(before_total), human_readable(after_total), (before_total - after_total)/before_total, processed_num))
else:
report(_('Images are already fully optimized'))
return changed, results