Use pillow to encode pages as webp
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
79a348acc9
commit
253914e245
|
@ -27,15 +27,12 @@ COPY --from=requirements /usr/src/app/requirements.txt .
|
||||||
|
|
||||||
RUN apk add --no-cache --virtual .deps \
|
RUN apk add --no-cache --virtual .deps \
|
||||||
build-base \
|
build-base \
|
||||||
git \
|
|
||||||
libffi-dev \
|
|
||||||
libjpeg-turbo-dev \
|
libjpeg-turbo-dev \
|
||||||
libwebp-dev \
|
libwebp-dev \
|
||||||
zlib-dev \
|
zlib-dev \
|
||||||
&& pip install -r requirements.txt \
|
&& pip install -r requirements.txt \
|
||||||
&& apk del .deps \
|
&& apk del .deps \
|
||||||
&& apk add --no-cache \
|
&& apk add --no-cache \
|
||||||
libffi \
|
|
||||||
libjpeg-turbo \
|
libjpeg-turbo \
|
||||||
libwebp
|
libwebp
|
||||||
|
|
||||||
|
|
1
Pipfile
1
Pipfile
|
@ -11,7 +11,6 @@ pillow = "*"
|
||||||
flask-cors = "*"
|
flask-cors = "*"
|
||||||
gunicorn = "*"
|
gunicorn = "*"
|
||||||
flask-caching = "*"
|
flask-caching = "*"
|
||||||
webp = {editable = true,git = "https://github.com/sbruder/pywebp"}
|
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.7"
|
python_version = "3.7"
|
||||||
|
|
67
Pipfile.lock
generated
67
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "5a623242219f0ec36e67df9c0caaadf71b39cfd21f5ed070f2766f9df8d3fd4d"
|
"sha256": "92afeeaf4d754a31e04e294f6974bd9616eb0f388ce3d977ae235f3d49fa2eae"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -16,39 +16,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"cffi": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774",
|
|
||||||
"sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d",
|
|
||||||
"sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90",
|
|
||||||
"sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b",
|
|
||||||
"sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63",
|
|
||||||
"sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45",
|
|
||||||
"sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25",
|
|
||||||
"sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3",
|
|
||||||
"sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b",
|
|
||||||
"sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647",
|
|
||||||
"sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016",
|
|
||||||
"sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4",
|
|
||||||
"sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb",
|
|
||||||
"sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753",
|
|
||||||
"sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7",
|
|
||||||
"sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9",
|
|
||||||
"sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f",
|
|
||||||
"sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8",
|
|
||||||
"sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f",
|
|
||||||
"sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc",
|
|
||||||
"sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42",
|
|
||||||
"sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3",
|
|
||||||
"sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909",
|
|
||||||
"sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45",
|
|
||||||
"sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d",
|
|
||||||
"sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512",
|
|
||||||
"sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff",
|
|
||||||
"sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201"
|
|
||||||
],
|
|
||||||
"version": "==1.12.3"
|
|
||||||
},
|
|
||||||
"click": {
|
"click": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||||
|
@ -135,27 +102,6 @@
|
||||||
],
|
],
|
||||||
"version": "==1.1.1"
|
"version": "==1.1.1"
|
||||||
},
|
},
|
||||||
"numpy": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:03e311b0a4c9f5755da7d52161280c6a78406c7be5c5cc7facfbcebb641efb7e",
|
|
||||||
"sha256:0cdd229a53d2720d21175012ab0599665f8c9588b3b8ffa6095dd7b90f0691dd",
|
|
||||||
"sha256:312bb18e95218bedc3563f26fcc9c1c6bfaaf9d453d15942c0839acdd7e4c473",
|
|
||||||
"sha256:464b1c48baf49e8505b1bb754c47a013d2c305c5b14269b5c85ea0625b6a988a",
|
|
||||||
"sha256:5adfde7bd3ee4864536e230bcab1c673f866736698724d5d28c11a4d63672658",
|
|
||||||
"sha256:7724e9e31ee72389d522b88c0d4201f24edc34277999701ccd4a5392e7d8af61",
|
|
||||||
"sha256:8d36f7c53ae741e23f54793ffefb2912340b800476eb0a831c6eb602e204c5c4",
|
|
||||||
"sha256:910d2272403c2ea8a52d9159827dc9f7c27fb4b263749dca884e2e4a8af3b302",
|
|
||||||
"sha256:951fefe2fb73f84c620bec4e001e80a80ddaa1b84dce244ded7f1e0cbe0ed34a",
|
|
||||||
"sha256:9588c6b4157f493edeb9378788dcd02cb9e6a6aeaa518b511a1c79d06cbd8094",
|
|
||||||
"sha256:9ce8300950f2f1d29d0e49c28ebfff0d2f1e2a7444830fbb0b913c7c08f31511",
|
|
||||||
"sha256:be39cca66cc6806652da97103605c7b65ee4442c638f04ff064a7efd9a81d50a",
|
|
||||||
"sha256:c3ab2d835b95ccb59d11dfcd56eb0480daea57cdf95d686d22eff35584bc4554",
|
|
||||||
"sha256:eb0fc4a492cb896346c9e2c7a22eae3e766d407df3eb20f4ce027f23f76e4c54",
|
|
||||||
"sha256:ec0c56eae6cee6299f41e780a0280318a93db519bbb2906103c43f3e2be1206c",
|
|
||||||
"sha256:f4e4612de60a4f1c4d06c8c2857cdcb2b8b5289189a12053f37d3f41f06c60d0"
|
|
||||||
],
|
|
||||||
"version": "==1.17.0"
|
|
||||||
},
|
|
||||||
"pillow": {
|
"pillow": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0804f77cb1e9b6dbd37601cee11283bba39a8d44b9ddb053400c58e0c0d7d9de",
|
"sha256:0804f77cb1e9b6dbd37601cee11283bba39a8d44b9ddb053400c58e0c0d7d9de",
|
||||||
|
@ -188,12 +134,6 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==6.1.0"
|
"version": "==6.1.0"
|
||||||
},
|
},
|
||||||
"pycparser": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
|
|
||||||
],
|
|
||||||
"version": "==2.19"
|
|
||||||
},
|
|
||||||
"six": {
|
"six": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||||
|
@ -201,11 +141,6 @@
|
||||||
],
|
],
|
||||||
"version": "==1.12.0"
|
"version": "==1.12.0"
|
||||||
},
|
},
|
||||||
"webp": {
|
|
||||||
"editable": true,
|
|
||||||
"git": "https://github.com/sbruder/pywebp",
|
|
||||||
"ref": "39e39c0e1071985b7944651cc13ec11834751ce3"
|
|
||||||
},
|
|
||||||
"werkzeug": {
|
"werkzeug": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
|
"sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
|
||||||
|
|
41
backend.py
41
backend.py
|
@ -6,7 +6,6 @@ from zipfile import ZipFile
|
||||||
from zlib import crc32
|
from zlib import crc32
|
||||||
import os.path
|
import os.path
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import webp
|
|
||||||
import werkzeug.exceptions as exceptions
|
import werkzeug.exceptions as exceptions
|
||||||
|
|
||||||
mimetypes['.webp'] = 'image/webp'
|
mimetypes['.webp'] = 'image/webp'
|
||||||
|
@ -52,24 +51,25 @@ def generate_thumbnail(filepath):
|
||||||
|
|
||||||
|
|
||||||
class CalibreDB:
|
class CalibreDB:
|
||||||
def __init__(self, path='metadata.db', enable_webp=True, webp_quality=80, webp_size=2048):
|
def __init__(self, path='metadata.db', enable_webp=True, webp_quality=80, webp_method=0, webp_size=2048):
|
||||||
self.database_path = f'file:{path}?mode=ro'
|
self.database_path = f'file:{path}?mode=ro'
|
||||||
|
|
||||||
self.webp = enable_webp
|
self.webp = enable_webp
|
||||||
if self.webp is True:
|
if self.webp is True:
|
||||||
if webp_quality == 101:
|
# lossy: 0-100 (used as quality)
|
||||||
lossless = True
|
# lossless: 101-201 (101 subtracted and used as quality)
|
||||||
webp_quality = 100
|
if webp_quality > 100:
|
||||||
|
webp_lossless = True
|
||||||
|
webp_quality = webp_quality - 101
|
||||||
else:
|
else:
|
||||||
lossless = False
|
webp_lossless = False
|
||||||
|
|
||||||
self.webp_config = webp.WebPConfig.new(
|
self.webp_config = {
|
||||||
preset=webp.WebPPreset.DRAWING,
|
'quality': webp_quality,
|
||||||
quality=webp_quality,
|
'method': webp_method,
|
||||||
lossless=lossless
|
'lossless': webp_lossless,
|
||||||
)
|
'size': webp_size
|
||||||
|
}
|
||||||
self.webp_size = webp_size
|
|
||||||
|
|
||||||
def create_cursor(self):
|
def create_cursor(self):
|
||||||
conn = sqlite3.connect(self.database_path, uri=True)
|
conn = sqlite3.connect(self.database_path, uri=True)
|
||||||
|
@ -241,10 +241,17 @@ class CalibreDB:
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
with volume.open(page_filename) as orig_page_data:
|
with volume.open(page_filename) as orig_page_data:
|
||||||
image = Image.open(orig_page_data)
|
image = Image.open(orig_page_data)
|
||||||
image.thumbnail((self.webp_size, self.webp_size))
|
image.thumbnail(tuple([self.webp_config['size']] * 2))
|
||||||
image = image.convert('RGB')
|
page_data = BytesIO()
|
||||||
image = webp.WebPPicture.from_pil(image)
|
image.save(
|
||||||
page_data = BytesIO(image.encode(self.webp_config).buffer())
|
page_data,
|
||||||
|
format='webp',
|
||||||
|
save_all=True, #
|
||||||
|
append_images=[image], # https://github.com/python-pillow/Pillow/issues/4042
|
||||||
|
quality=self.webp_config['quality'],
|
||||||
|
method=self.webp_config['method'],
|
||||||
|
lossless=self.webp_config['lossless']
|
||||||
|
)
|
||||||
|
|
||||||
disk_cache.set(f'{volume_id}-{page_number}', page_data)
|
disk_cache.set(f'{volume_id}-{page_number}', page_data)
|
||||||
page_data.seek(0)
|
page_data.seek(0)
|
||||||
|
|
Reference in a new issue