mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-26 01:50:31 +00:00
Remove Pillow as dependency
This commit is contained in:
parent
d957b2d20f
commit
352b4a0b73
44
cps/comic.py
44
cps/comic.py
@ -18,21 +18,21 @@
|
|||||||
|
|
||||||
from __future__ import division, print_function, unicode_literals
|
from __future__ import division, print_function, unicode_literals
|
||||||
import os
|
import os
|
||||||
import io
|
|
||||||
|
|
||||||
from . import logger, isoLanguages
|
from . import logger, isoLanguages
|
||||||
from .constants import BookMeta
|
from .constants import BookMeta
|
||||||
|
|
||||||
try:
|
|
||||||
from PIL import Image as PILImage
|
|
||||||
use_PIL = True
|
|
||||||
except ImportError as e:
|
|
||||||
use_PIL = False
|
|
||||||
|
|
||||||
|
|
||||||
log = logger.create()
|
log = logger.create()
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from wand.image import Image
|
||||||
|
use_IM = True
|
||||||
|
except (ImportError, RuntimeError) as e:
|
||||||
|
use_IM = False
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from comicapi.comicarchive import ComicArchive, MetaDataStyle
|
from comicapi.comicarchive import ComicArchive, MetaDataStyle
|
||||||
use_comic_meta = True
|
use_comic_meta = True
|
||||||
@ -52,20 +52,26 @@ except (ImportError, LookupError) as e:
|
|||||||
use_rarfile = False
|
use_rarfile = False
|
||||||
use_comic_meta = False
|
use_comic_meta = False
|
||||||
|
|
||||||
|
COVER_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.webp', '.bmp']
|
||||||
|
|
||||||
|
|
||||||
def _cover_processing(tmp_file_name, img, extension):
|
def _cover_processing(tmp_file_name, img, extension):
|
||||||
if use_PIL:
|
tmp_cover_name = os.path.join(os.path.dirname(tmp_file_name), 'cover.jpg')
|
||||||
|
if use_IM:
|
||||||
# convert to jpg because calibre only supports jpg
|
# convert to jpg because calibre only supports jpg
|
||||||
if extension in ('.png', '.webp'):
|
cover_ext = COVER_EXTENSIONS
|
||||||
imgc = PILImage.open(io.BytesIO(img))
|
cover_ext.remove('.jpeg')
|
||||||
im = imgc.convert('RGB')
|
cover_ext.remove('.jpg')
|
||||||
tmp_bytesio = io.BytesIO()
|
if extension in cover_ext:
|
||||||
im.save(tmp_bytesio, format='JPEG')
|
with Image(filename=tmp_file_name) as imgc:
|
||||||
img = tmp_bytesio.getvalue()
|
imgc.format = 'jpeg'
|
||||||
|
imgc.transform_colorspace('rgb')
|
||||||
|
imgc.save(tmp_cover_name)
|
||||||
|
return tmp_cover_name
|
||||||
|
|
||||||
if not img:
|
if not img:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
tmp_cover_name = os.path.join(os.path.dirname(tmp_file_name), 'cover.jpg')
|
|
||||||
with open(tmp_cover_name, 'wb') as f:
|
with open(tmp_cover_name, 'wb') as f:
|
||||||
f.write(img)
|
f.write(img)
|
||||||
return tmp_cover_name
|
return tmp_cover_name
|
||||||
@ -80,7 +86,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
|
|||||||
ext = os.path.splitext(name)
|
ext = os.path.splitext(name)
|
||||||
if len(ext) > 1:
|
if len(ext) > 1:
|
||||||
extension = ext[1].lower()
|
extension = ext[1].lower()
|
||||||
if extension in ('.jpg', '.jpeg', '.png', '.webp'):
|
if extension in COVER_EXTENSIONS:
|
||||||
cover_data = archive.getPage(index)
|
cover_data = archive.getPage(index)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
@ -90,7 +96,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
|
|||||||
ext = os.path.splitext(name)
|
ext = os.path.splitext(name)
|
||||||
if len(ext) > 1:
|
if len(ext) > 1:
|
||||||
extension = ext[1].lower()
|
extension = ext[1].lower()
|
||||||
if extension in ('.jpg', '.jpeg', '.png', '.webp'):
|
if extension in COVER_EXTENSIONS:
|
||||||
cover_data = cf.read(name)
|
cover_data = cf.read(name)
|
||||||
break
|
break
|
||||||
elif original_file_extension.upper() == '.CBT':
|
elif original_file_extension.upper() == '.CBT':
|
||||||
@ -99,7 +105,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
|
|||||||
ext = os.path.splitext(name)
|
ext = os.path.splitext(name)
|
||||||
if len(ext) > 1:
|
if len(ext) > 1:
|
||||||
extension = ext[1].lower()
|
extension = ext[1].lower()
|
||||||
if extension in ('.jpg', '.jpeg', '.png', '.webp'):
|
if extension in COVER_EXTENSIONS:
|
||||||
cover_data = cf.extractfile(name).read()
|
cover_data = cf.extractfile(name).read()
|
||||||
break
|
break
|
||||||
elif original_file_extension.upper() == '.CBR' and use_rarfile:
|
elif original_file_extension.upper() == '.CBR' and use_rarfile:
|
||||||
@ -110,7 +116,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
|
|||||||
ext = os.path.splitext(name)
|
ext = os.path.splitext(name)
|
||||||
if len(ext) > 1:
|
if len(ext) > 1:
|
||||||
extension = ext[1].lower()
|
extension = ext[1].lower()
|
||||||
if extension in ('.jpg', '.jpeg', '.png', '.webp'):
|
if extension in COVER_EXTENSIONS:
|
||||||
cover_data = cf.read(name)
|
cover_data = cf.read(name)
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -50,13 +50,6 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
use_unidecode = False
|
use_unidecode = False
|
||||||
|
|
||||||
try:
|
|
||||||
from PIL import Image as PILImage
|
|
||||||
from PIL import UnidentifiedImageError
|
|
||||||
use_PIL = True
|
|
||||||
except ImportError:
|
|
||||||
use_PIL = False
|
|
||||||
|
|
||||||
from . import calibre_db
|
from . import calibre_db
|
||||||
from .tasks.convert import TaskConvert
|
from .tasks.convert import TaskConvert
|
||||||
from . import logger, config, get_locale, db, ub
|
from . import logger, config, get_locale, db, ub
|
||||||
@ -66,9 +59,15 @@ from .subproc_wrapper import process_wait
|
|||||||
from .services.worker import WorkerThread, STAT_WAITING, STAT_FAIL, STAT_STARTED, STAT_FINISH_SUCCESS
|
from .services.worker import WorkerThread, STAT_WAITING, STAT_FAIL, STAT_STARTED, STAT_FINISH_SUCCESS
|
||||||
from .tasks.mail import TaskEmail
|
from .tasks.mail import TaskEmail
|
||||||
|
|
||||||
|
|
||||||
log = logger.create()
|
log = logger.create()
|
||||||
|
|
||||||
|
try:
|
||||||
|
from wand.image import Image
|
||||||
|
use_IM = True
|
||||||
|
except (ImportError, RuntimeError) as e:
|
||||||
|
log.debug('Cannot import Image, generating covers from non jpg files will not work: %s', e)
|
||||||
|
use_IM = False
|
||||||
|
|
||||||
|
|
||||||
# Convert existing book entry to new format
|
# Convert existing book entry to new format
|
||||||
def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, user_id, kindle_mail=None):
|
def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, user_id, kindle_mail=None):
|
||||||
@ -109,21 +108,21 @@ def convert_book_format(book_id, calibrepath, old_book_format, new_book_format,
|
|||||||
def send_test_mail(kindle_mail, user_name):
|
def send_test_mail(kindle_mail, user_name):
|
||||||
WorkerThread.add(user_name, TaskEmail(_(u'Calibre-Web test e-mail'), None, None,
|
WorkerThread.add(user_name, TaskEmail(_(u'Calibre-Web test e-mail'), None, None,
|
||||||
config.get_mail_settings(), kindle_mail, _(u"Test e-mail"),
|
config.get_mail_settings(), kindle_mail, _(u"Test e-mail"),
|
||||||
_(u'This e-mail has been sent via Calibre-Web.')))
|
_(u'This e-mail has been sent via Calibre-Web.')))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# Send registration email or password reset email, depending on parameter resend (False means welcome email)
|
# Send registration email or password reset email, depending on parameter resend (False means welcome email)
|
||||||
def send_registration_mail(e_mail, user_name, default_password, resend=False):
|
def send_registration_mail(e_mail, user_name, default_password, resend=False):
|
||||||
text = "Hello %s!\r\n" % user_name
|
txt = "Hello %s!\r\n" % user_name
|
||||||
if not resend:
|
if not resend:
|
||||||
text += "Your new account at Calibre-Web has been created. Thanks for joining us!\r\n"
|
txt += "Your new account at Calibre-Web has been created. Thanks for joining us!\r\n"
|
||||||
text += "Please log in to your account using the following informations:\r\n"
|
txt += "Please log in to your account using the following informations:\r\n"
|
||||||
text += "User name: %s\r\n" % user_name
|
txt += "User name: %s\r\n" % user_name
|
||||||
text += "Password: %s\r\n" % default_password
|
txt += "Password: %s\r\n" % default_password
|
||||||
text += "Don't forget to change your password after first login.\r\n"
|
txt += "Don't forget to change your password after first login.\r\n"
|
||||||
text += "Sincerely\r\n\r\n"
|
txt += "Sincerely\r\n\r\n"
|
||||||
text += "Your Calibre-Web team"
|
txt += "Your Calibre-Web team"
|
||||||
WorkerThread.add(None, TaskEmail(
|
WorkerThread.add(None, TaskEmail(
|
||||||
subject=_(u'Get Started with Calibre-Web'),
|
subject=_(u'Get Started with Calibre-Web'),
|
||||||
filepath=None,
|
filepath=None,
|
||||||
@ -131,7 +130,7 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
|
|||||||
settings=config.get_mail_settings(),
|
settings=config.get_mail_settings(),
|
||||||
recipient=e_mail,
|
recipient=e_mail,
|
||||||
taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name),
|
taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name),
|
||||||
text=text
|
text=txt
|
||||||
))
|
))
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -177,7 +176,7 @@ def check_send_to_kindle(entry):
|
|||||||
'convert': 0,
|
'convert': 0,
|
||||||
'text': _('Send %(format)s to Kindle', format='Pdf')})
|
'text': _('Send %(format)s to Kindle', format='Pdf')})
|
||||||
if config.config_converterpath:
|
if config.config_converterpath:
|
||||||
if 'EPUB' in formats and not 'MOBI' in formats:
|
if 'EPUB' in formats and 'MOBI' not in formats:
|
||||||
bookformats.append({'format': 'Mobi',
|
bookformats.append({'format': 'Mobi',
|
||||||
'convert':1,
|
'convert':1,
|
||||||
'text': _('Convert %(orig)s to %(format)s and send to Kindle',
|
'text': _('Convert %(orig)s to %(format)s and send to Kindle',
|
||||||
@ -586,16 +585,15 @@ def save_cover_from_url(url, book_path):
|
|||||||
requests.exceptions.Timeout) as ex:
|
requests.exceptions.Timeout) as ex:
|
||||||
log.info(u'Cover Download Error %s', ex)
|
log.info(u'Cover Download Error %s', ex)
|
||||||
return False, _("Error Downloading Cover")
|
return False, _("Error Downloading Cover")
|
||||||
except UnidentifiedImageError as ex:
|
# except UnidentifiedImageError as ex:
|
||||||
log.info(u'File Format Error %s', ex)
|
# log.info(u'File Format Error %s', ex)
|
||||||
return False, _("Cover Format Error")
|
# return False, _("Cover Format Error")
|
||||||
|
|
||||||
|
|
||||||
def save_cover_from_filestorage(filepath, saved_filename, img):
|
def save_cover_from_filestorage(filepath, saved_filename, img):
|
||||||
if hasattr(img, '_content'):
|
if hasattr(img,"metadata"):
|
||||||
f = open(os.path.join(filepath, saved_filename), "wb")
|
img.save(filename=os.path.join(filepath, saved_filename))
|
||||||
f.write(img._content)
|
img.close()
|
||||||
f.close()
|
|
||||||
else:
|
else:
|
||||||
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
|
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
|
||||||
if not os.path.exists(filepath):
|
if not os.path.exists(filepath):
|
||||||
@ -616,20 +614,19 @@ def save_cover_from_filestorage(filepath, saved_filename, img):
|
|||||||
def save_cover(img, book_path):
|
def save_cover(img, book_path):
|
||||||
content_type = img.headers.get('content-type')
|
content_type = img.headers.get('content-type')
|
||||||
|
|
||||||
if use_PIL:
|
if use_IM:
|
||||||
if content_type not in ('image/jpeg', 'image/png', 'image/webp'):
|
if content_type not in ('image/jpeg', 'image/png', 'image/webp', 'image/bmp'):
|
||||||
log.error("Only jpg/jpeg/png/webp files are supported as coverfile")
|
log.error("Only jpg/jpeg/png/webp/bmp files are supported as coverfile")
|
||||||
return False, _("Only jpg/jpeg/png/webp files are supported as coverfile")
|
return False, _("Only jpg/jpeg/png/webp/bmp files are supported as coverfile")
|
||||||
# convert to jpg because calibre only supports jpg
|
# convert to jpg because calibre only supports jpg
|
||||||
if content_type in ('image/png', 'image/webp'):
|
if content_type != 'image/jpg':
|
||||||
if hasattr(img, 'stream'):
|
if hasattr(img, 'stream'):
|
||||||
imgc = PILImage.open(img.stream)
|
imgc = Image(blob=img.stream)
|
||||||
else:
|
else:
|
||||||
imgc = PILImage.open(io.BytesIO(img.content))
|
imgc = Image(blob=io.BytesIO(img.content))
|
||||||
im = imgc.convert('RGB')
|
imgc.format = 'jpeg'
|
||||||
tmp_bytesio = io.BytesIO()
|
imgc.transform_colorspace("rgb")
|
||||||
im.save(tmp_bytesio, format='JPEG')
|
img = imgc
|
||||||
img._content = tmp_bytesio.getvalue()
|
|
||||||
else:
|
else:
|
||||||
if content_type not in 'image/jpeg':
|
if content_type not in 'image/jpeg':
|
||||||
log.error("Only jpg/jpeg files are supported as coverfile")
|
log.error("Only jpg/jpeg files are supported as coverfile")
|
||||||
|
@ -66,14 +66,6 @@ except ImportError as e:
|
|||||||
log.debug('Cannot import fb2, extracting fb2 metadata will not work: %s', e)
|
log.debug('Cannot import fb2, extracting fb2 metadata will not work: %s', e)
|
||||||
use_fb2_meta = False
|
use_fb2_meta = False
|
||||||
|
|
||||||
try:
|
|
||||||
from PIL import Image as PILImage
|
|
||||||
from PIL import __version__ as PILversion
|
|
||||||
use_PIL = True
|
|
||||||
except ImportError as e:
|
|
||||||
log.debug('Cannot import Pillow, using png and webp images as cover will not work: %s', e)
|
|
||||||
use_PIL = False
|
|
||||||
|
|
||||||
|
|
||||||
def process(tmp_file_path, original_file_name, original_file_extension, rarExecutable):
|
def process(tmp_file_path, original_file_name, original_file_extension, rarExecutable):
|
||||||
meta = None
|
meta = None
|
||||||
@ -179,10 +171,6 @@ def get_versions():
|
|||||||
XVersion = 'v'+'.'.join(map(str, lxmlversion))
|
XVersion = 'v'+'.'.join(map(str, lxmlversion))
|
||||||
else:
|
else:
|
||||||
XVersion = u'not installed'
|
XVersion = u'not installed'
|
||||||
if use_PIL:
|
|
||||||
PILVersion = 'v' + PILversion
|
|
||||||
else:
|
|
||||||
PILVersion = u'not installed'
|
|
||||||
if comic.use_comic_meta:
|
if comic.use_comic_meta:
|
||||||
ComicVersion = comic.comic_version or u'installed'
|
ComicVersion = comic.comic_version or u'installed'
|
||||||
else:
|
else:
|
||||||
@ -191,7 +179,7 @@ def get_versions():
|
|||||||
'PyPdf': PVersion,
|
'PyPdf': PVersion,
|
||||||
'lxml':XVersion,
|
'lxml':XVersion,
|
||||||
'Wand': WVersion,
|
'Wand': WVersion,
|
||||||
'Pillow': PILVersion,
|
# 'Pillow': PILVersion,
|
||||||
'Comic_API': ComicVersion}
|
'Comic_API': ComicVersion}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ SQLAlchemy-Utils>=0.33.5,<0.37.0
|
|||||||
|
|
||||||
# extracting metadata
|
# extracting metadata
|
||||||
lxml>=3.8.0,<4.6.0
|
lxml>=3.8.0,<4.6.0
|
||||||
Pillow>=4.0.0,<7.2.0
|
|
||||||
rarfile>=2.7
|
rarfile>=2.7
|
||||||
|
|
||||||
# other
|
# other
|
||||||
|
Loading…
Reference in New Issue
Block a user