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 - - 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 + 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) + 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 @@
- +
diff --git a/cps/web.py b/cps/web.py index 0eb8e44e..9b6f47af 100644 --- a/cps/web.py +++ b/cps/web.py @@ -3558,33 +3558,19 @@ def upload_single_file(request, book, book_id): helper.global_WorkerThread.add_upload(current_user.nickname, "" + uploadText + "") + def upload_cover(request, book): if 'btn-upload-cover' in request.files: requested_file = request.files['btn-upload-cover'] # check for empty request if requested_file.filename != '': - file_ext = requested_file.filename.rsplit('.', 1)[-1].lower() - filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path)) - saved_filename = os.path.join(filepath, 'cover.' + file_ext) - - # 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: - flash(_(u"Failed to create path for cover %(path)s (Permission denied).", cover=filepath), - category="error") - return redirect(url_for('show_book', book_id=book.id)) - try: - requested_file.save(saved_filename) - # im=Image.open(saved_filename) - book.has_cover = 1 - except OSError: - flash(_(u"Failed to store cover-file %(cover)s.", cover=saved_filename), category="error") - return redirect(url_for('show_book', book_id=book.id)) - except IOError: - flash(_(u"Cover-file is not a valid image file" % saved_filename), category="error") - return redirect(url_for('show_book', book_id=book.id)) + if helper.save_cover(requested_file, book.path) is True: + return True + else: + # ToDo Message not always coorect + flash(_(u"Cover is not a supported imageformat (jpg/png/webp), can't save"), category="error") + return False + return None @app.route("/admin/book/", methods=['GET', 'POST']) @login_required_if_no_ano @@ -3605,7 +3591,8 @@ def edit_book(book_id): return redirect(url_for("index")) upload_single_file(request, book, book_id) - upload_cover(request, book) + if upload_cover(request, book) is True: + book.has_cover = 1 try: to_save = request.form.to_dict() # Update book @@ -3651,10 +3638,10 @@ def edit_book(book_id): if not error: if to_save["cover_url"]: - if helper.save_cover(to_save["cover_url"], book.path) is True: + if helper.save_cover_from_url(to_save["cover_url"], book.path) is True: book.has_cover = 1 else: - flash(_(u"Cover is not a jpg file, can't save"), category="error") + flash(_(u"Cover is not a supported imageformat (jpg/png/webp), can't save"), category="error") if book.series_index != to_save["series_index"]: book.series_index = to_save["series_index"] diff --git a/requirements.txt b/requirements.txt index 3fb23ea3..84ffdd7c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ SQLAlchemy>=1.1.0 tornado>=4.1 Wand>=0.4.4 unidecode>=0.04.19 +Pillow>=5.4.0 \ No newline at end of file