diff --git a/cps/book_formats.py b/cps/book_formats.py index 36212732..fb08caa9 100644 --- a/cps/book_formats.py +++ b/cps/book_formats.py @@ -62,6 +62,8 @@ except ImportError as e: logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e) use_fb2_meta = False +from PIL import Image + def process(tmp_file_path, original_file_name, original_file_extension): meta = None @@ -131,6 +133,47 @@ def pdf_preview(tmp_file_path, tmp_dir): if use_generic_pdf_cover: return None else: + try: + input1 = PdfFileReader(open(tmp_file_path, 'rb'), strict=False) + page0 = input1.getPage(0) + xObject = page0['/Resources']['/XObject'].getObject() + + for obj in xObject: + if xObject[obj]['/Subtype'] == '/Image': + size = (xObject[obj]['/Width'], xObject[obj]['/Height']) + data = xObject[obj]._data # xObject[obj].getData() + if xObject[obj]['/ColorSpace'] == '/DeviceRGB': + mode = "RGB" + else: + mode = "P" + if '/Filter' in xObject[obj]: + if xObject[obj]['/Filter'] == '/FlateDecode': + img = Image.frombytes(mode, size, data) + cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.png" + img.save(filename=os.path.join(tmp_dir, cover_file_name)) + return cover_file_name + # img.save(obj[1:] + ".png") + elif xObject[obj]['/Filter'] == '/DCTDecode': + cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg" + img = open(cover_file_name, "wb") + img.write(data) + img.close() + return cover_file_name + elif xObject[obj]['/Filter'] == '/JPXDecode': + cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jp2" + img = open(cover_file_name, "wb") + img.write(data) + img.close() + return cover_file_name + else: + img = Image.frombytes(mode, size, data) + cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.png" + img.save(filename=os.path.join(tmp_dir, cover_file_name)) + return cover_file_name + # img.save(obj[1:] + ".png") + except Exception as ex: + print(ex) + try: cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg" with Image(filename=tmp_file_path + "[0]", resolution=150) as img: diff --git a/cps/helper.py b/cps/helper.py index ea9e035c..aa832e42 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -24,6 +24,7 @@ import ub from flask import current_app as app from tempfile import gettempdir import sys +import io import os import re import unicodedata @@ -34,6 +35,7 @@ from flask_babel import gettext as _ from flask_login import current_user from babel.dates import format_datetime from datetime import datetime +from PIL import Image import shutil import requests try: @@ -442,27 +444,66 @@ def get_book_cover(cover_path): return send_from_directory(os.path.join(ub.config.config_calibre_dir, cover_path), "cover.jpg") -# saves book cover to gdrive or locally -def save_cover(url, book_path): +# saves book cover from url +def save_cover_from_url(url, book_path): img = requests.get(url) - if img.headers.get('content-type') != 'image/jpeg': - web.app.logger.error("Cover is no jpg file, can't save") + return save_cover(img, book_path) + + +def save_cover_from_filestorage(filepath, saved_filename, img): + if hasattr(img,'_content'): + f = open(os.path.join(filepath, saved_filename), "wb") + f.write(img._content) + f.close() + else: + # check if file path exists, otherwise create it, copy file to calibre path and delete temp file + if not os.path.exists(filepath): + try: + os.makedirs(filepath) + except OSError: + web.app.logger.error(u"Failed to create path for cover") + return False + try: + img.save(os.path.join(filepath, saved_filename)) + except OSError: + web.app.logger.error(u"Failed to store cover-file") + return False + except IOError: + web.app.logger.error(u"Cover-file is not a valid image file") + return False + return True + + +# saves book cover to gdrive or locally +def save_cover(img, book_path): + content_type = img.headers.get('content-type') + if content_type not in ('image/jpeg', 'image/png', 'image/webp'): + web.app.logger.error("Only jpg/jpeg/png/webp files are supported as coverfile") return False + # convert to jpg because calibre only supports jpg + if content_type in ('image/png', 'image/webp'): + if hasattr(img,'stream'): + imgc = Image.open(img.stream) + else: + imgc = Image.open(io.BytesIO(img.content)) + im = imgc.convert('RGB') + tmp_bytesio = io.BytesIO() + im.save(tmp_bytesio, format='JPEG') + img._content = tmp_bytesio.getvalue() + if ub.config.config_use_google_drive: tmpDir = gettempdir() - f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb") - f.write(img.content) - f.close() - gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'), os.path.join(tmpDir, f.name)) - web.app.logger.info("Cover is saved on Google Drive") - return True + if save_cover_from_filestorage(tmpDir, "uploaded_cover.jpg", img) is True: + gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'), + os.path.join(tmpDir, "uploaded_cover.jpg")) + web.app.logger.info("Cover is saved on Google Drive") + return True + else: + return False + else: + return save_cover_from_filestorage(os.path.join(ub.config.config_calibre_dir, book_path), "cover.jpg", img) - f = open(os.path.join(ub.config.config_calibre_dir, book_path, "cover.jpg"), "wb") - f.write(img.content) - f.close() - web.app.logger.info("Cover is saved") - return True def do_download_file(book, book_format, data, headers): @@ -487,7 +528,6 @@ def do_download_file(book, book_format, data, headers): - def check_unrar(unrarLocation): error = False if os.path.exists(unrarLocation): diff --git a/cps/templates/book_edit.html b/cps/templates/book_edit.html index 4b344173..9d2b2c76 100644 --- a/cps/templates/book_edit.html +++ b/cps/templates/book_edit.html @@ -90,7 +90,7 @@