From 0e6e5afe8dcbe76bd09c2bb6d23dc8f305726c91 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 10 Mar 2020 10:00:35 +0530 Subject: [PATCH] MOBI Output: Improve conversion of PNG images with transparency to GIF --- src/calibre/ebooks/mobi/utils.py | 9 ++------- src/calibre/utils/img.py | 32 +++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/calibre/ebooks/mobi/utils.py b/src/calibre/ebooks/mobi/utils.py index faf7e5a6b5..0121777702 100644 --- a/src/calibre/ebooks/mobi/utils.py +++ b/src/calibre/ebooks/mobi/utils.py @@ -10,7 +10,7 @@ import struct, string, zlib, os from collections import OrderedDict from io import BytesIO -from calibre.utils.img import save_cover_data_to, scale_image, image_to_data, image_from_data, resize_image +from calibre.utils.img import save_cover_data_to, scale_image, image_to_data, image_from_data, resize_image, png_data_to_gif_data from calibre.utils.imghdr import what from calibre.ebooks import normalize from polyglot.builtins import unicode_type, range, as_bytes, map @@ -417,13 +417,8 @@ def to_base(num, base=32, min_num_digits=None): def mobify_image(data): 'Convert PNG images to GIF as the idiotic Kindle cannot display some PNG' fmt = what(None, data) - if fmt == 'png': - from PIL import Image - im = Image.open(BytesIO(data)) - buf = BytesIO() - im.save(buf, 'gif') - data = buf.getvalue() + data = png_data_to_gif_data(data) return data # Font records {{{ diff --git a/src/calibre/utils/img.py b/src/calibre/utils/img.py index bf10b2b7af..71d1966138 100644 --- a/src/calibre/utils/img.py +++ b/src/calibre/utils/img.py @@ -67,6 +67,32 @@ def load_jxr_data(data): # }}} +# png to gif {{{ + + +def png_data_to_gif_data(data): + from PIL import Image + img = Image.open(BytesIO(data)) + buf = BytesIO() + if img.mode in ('p', 'P'): + transparency = img.info.get('transparency') + if transparency is not None: + img.save(buf, 'gif', transparency=transparency) + else: + img.save(buf, 'gif') + elif img.mode in ('rgba', 'RGBA'): + alpha = img.split()[3] + mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0) + img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) + img.paste(255, mask) + img.save(buf, 'gif', transparency=255) + else: + img = img.convert('P', palette=Image.ADAPTIVE) + img.save(buf, 'gif') + return buf.getvalue() + +# }}} + # Loading images {{{ @@ -140,11 +166,7 @@ def image_to_data(img, compression_quality=95, fmt='JPEG', png_compression_level w.setQuality(90) if not w.write(img): raise ValueError('Failed to export image as ' + fmt + ' with error: ' + w.errorString()) - from PIL import Image - im = Image.open(BytesIO(ba.data())) - buf = BytesIO() - im.save(buf, 'gif') - return buf.getvalue() + return png_data_to_gif_data(ba.data()) is_jpeg = fmt in ('JPG', 'JPEG') w = QImageWriter(buf, fmt.encode('ascii')) if is_jpeg: