mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-25 02:57:22 +00:00
Merge remote-tracking branch 'image_formats/dev'
This commit is contained in:
commit
91ebe33879
@ -62,6 +62,8 @@ except ImportError as e:
|
|||||||
logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
|
logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
|
||||||
use_fb2_meta = False
|
use_fb2_meta = False
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
def process(tmp_file_path, original_file_name, original_file_extension):
|
def process(tmp_file_path, original_file_name, original_file_extension):
|
||||||
meta = None
|
meta = None
|
||||||
@ -131,6 +133,47 @@ def pdf_preview(tmp_file_path, tmp_dir):
|
|||||||
if use_generic_pdf_cover:
|
if use_generic_pdf_cover:
|
||||||
return None
|
return None
|
||||||
else:
|
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:
|
try:
|
||||||
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
|
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
|
||||||
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
|
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
|
||||||
|
@ -24,6 +24,7 @@ import ub
|
|||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
import sys
|
import sys
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
@ -34,6 +35,7 @@ from flask_babel import gettext as _
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from babel.dates import format_datetime
|
from babel.dates import format_datetime
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from PIL import Image
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import requests
|
||||||
try:
|
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")
|
return send_from_directory(os.path.join(ub.config.config_calibre_dir, cover_path), "cover.jpg")
|
||||||
|
|
||||||
|
|
||||||
# saves book cover to gdrive or locally
|
# saves book cover from url
|
||||||
def save_cover(url, book_path):
|
def save_cover_from_url(url, book_path):
|
||||||
img = requests.get(url)
|
img = requests.get(url)
|
||||||
if img.headers.get('content-type') != 'image/jpeg':
|
return save_cover(img, book_path)
|
||||||
web.app.logger.error("Cover is no jpg file, can't save")
|
|
||||||
|
|
||||||
|
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
|
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:
|
if ub.config.config_use_google_drive:
|
||||||
tmpDir = gettempdir()
|
tmpDir = gettempdir()
|
||||||
f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb")
|
if save_cover_from_filestorage(tmpDir, "uploaded_cover.jpg", img) is True:
|
||||||
f.write(img.content)
|
gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'),
|
||||||
f.close()
|
os.path.join(tmpDir, "uploaded_cover.jpg"))
|
||||||
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")
|
web.app.logger.info("Cover is saved on Google Drive")
|
||||||
return True
|
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):
|
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):
|
def check_unrar(unrarLocation):
|
||||||
error = False
|
error = False
|
||||||
if os.path.exists(unrarLocation):
|
if os.path.exists(unrarLocation):
|
||||||
|
@ -90,7 +90,7 @@
|
|||||||
<div class="form-group" aria-label="Upload cover from local drive">
|
<div class="form-group" aria-label="Upload cover from local drive">
|
||||||
<label class="btn btn-primary btn-file" for="btn-upload-cover">{{ _('Upload Cover from local drive') }}</label>
|
<label class="btn btn-primary btn-file" for="btn-upload-cover">{{ _('Upload Cover from local drive') }}</label>
|
||||||
<div class="upload-cover-input-text" id="upload-cover"></div>
|
<div class="upload-cover-input-text" id="upload-cover"></div>
|
||||||
<input id="btn-upload-cover" name="btn-upload-cover" type="file">
|
<input id="btn-upload-cover" name="btn-upload-cover" type="file" accept=".jpg, .jpeg, .png, .webp">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="pubdate">{{_('Publishing date')}}</label>
|
<label for="pubdate">{{_('Publishing date')}}</label>
|
||||||
|
37
cps/web.py
37
cps/web.py
@ -3558,33 +3558,19 @@ def upload_single_file(request, book, book_id):
|
|||||||
helper.global_WorkerThread.add_upload(current_user.nickname,
|
helper.global_WorkerThread.add_upload(current_user.nickname,
|
||||||
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
||||||
|
|
||||||
|
|
||||||
def upload_cover(request, book):
|
def upload_cover(request, book):
|
||||||
if 'btn-upload-cover' in request.files:
|
if 'btn-upload-cover' in request.files:
|
||||||
requested_file = request.files['btn-upload-cover']
|
requested_file = request.files['btn-upload-cover']
|
||||||
# check for empty request
|
# check for empty request
|
||||||
if requested_file.filename != '':
|
if requested_file.filename != '':
|
||||||
file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
|
if helper.save_cover(requested_file, book.path) is True:
|
||||||
filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
|
return True
|
||||||
saved_filename = os.path.join(filepath, 'cover.' + file_ext)
|
else:
|
||||||
|
# ToDo Message not always coorect
|
||||||
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
|
flash(_(u"Cover is not a supported imageformat (jpg/png/webp), can't save"), category="error")
|
||||||
if not os.path.exists(filepath):
|
return False
|
||||||
try:
|
return None
|
||||||
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))
|
|
||||||
|
|
||||||
@app.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
|
@app.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
@ -3605,7 +3591,8 @@ def edit_book(book_id):
|
|||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
upload_single_file(request, book, book_id)
|
upload_single_file(request, book, book_id)
|
||||||
upload_cover(request, book)
|
if upload_cover(request, book) is True:
|
||||||
|
book.has_cover = 1
|
||||||
try:
|
try:
|
||||||
to_save = request.form.to_dict()
|
to_save = request.form.to_dict()
|
||||||
# Update book
|
# Update book
|
||||||
@ -3651,10 +3638,10 @@ def edit_book(book_id):
|
|||||||
|
|
||||||
if not error:
|
if not error:
|
||||||
if to_save["cover_url"]:
|
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
|
book.has_cover = 1
|
||||||
else:
|
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"]:
|
if book.series_index != to_save["series_index"]:
|
||||||
book.series_index = to_save["series_index"]
|
book.series_index = to_save["series_index"]
|
||||||
|
@ -13,3 +13,4 @@ SQLAlchemy>=1.1.0
|
|||||||
tornado>=4.1
|
tornado>=4.1
|
||||||
Wand>=0.4.4
|
Wand>=0.4.4
|
||||||
unidecode>=0.04.19
|
unidecode>=0.04.19
|
||||||
|
Pillow>=5.4.0
|
Loading…
Reference in New Issue
Block a user