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