Convert pages to webp

This commit is contained in:
Simon Bruder 2019-08-07 18:15:56 +00:00
parent 8949744657
commit 7c8ee5b70f
No known key found for this signature in database
GPG key ID: 6F03E0000CC5B62F
4 changed files with 105 additions and 7 deletions

View file

@ -11,7 +11,8 @@ FROM python:3-alpine as requirements
WORKDIR /usr/src/app/ WORKDIR /usr/src/app/
RUN pip install --no-cache-dir pipenv RUN apk add --no-cache git \
&& pip install --no-cache-dir pipenv
COPY Pipfile . COPY Pipfile .
COPY Pipfile.lock . COPY Pipfile.lock .
@ -26,12 +27,15 @@ 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

View file

@ -11,6 +11,7 @@ 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
View file

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "92afeeaf4d754a31e04e294f6974bd9616eb0f388ce3d977ae235f3d49fa2eae" "sha256": "5a623242219f0ec36e67df9c0caaadf71b39cfd21f5ed070f2766f9df8d3fd4d"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -16,6 +16,39 @@
] ]
}, },
"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",
@ -102,6 +135,27 @@
], ],
"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",
@ -134,6 +188,12 @@
"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",
@ -141,6 +201,11 @@
], ],
"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",

View file

@ -5,6 +5,7 @@ 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'
@ -46,9 +47,25 @@ def generate_thumbnail(filepath):
class CalibreDB: class CalibreDB:
def __init__(self, path='metadata.db'): def __init__(self, path='metadata.db', enable_webp=True, webp_quality=80, webp_size=2048):
self.database_path = f'file:{path}?mode=ro' self.database_path = f'file:{path}?mode=ro'
self.webp = enable_webp
if self.webp is True:
if webp_quality == 101:
lossless = True
webp_quality = 100
else:
lossless = False
self.webp_config = webp.WebPConfig.new(
preset=webp.WebPPreset.DRAWING,
quality=webp_quality,
lossless=lossless
)
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)
conn.row_factory = dict_factory conn.row_factory = dict_factory
@ -209,13 +226,24 @@ class CalibreDB:
return None return None
page_filename = zip_info.filename page_filename = zip_info.filename
mimetype = mimetypes[os.path.splitext(page_filename)[1]]
page_data = BytesIO() if self.webp is True and mimetype != 'image/webp':
page_data.write(volume.read(page_filename)) mimetype = 'image/webp'
page_data.seek(0)
with volume.open(page_filename) as orig_page_data:
image = Image.open(orig_page_data)
image.thumbnail((self.webp_size, self.webp_size))
image = image.convert('RGB')
image = webp.WebPPicture.from_pil(image)
page_data = BytesIO(image.encode(self.webp_config).buffer())
else:
page_data = BytesIO()
page_data.write(volume.read(page_filename))
page_data.seek(0)
return { return {
'data': page_data, 'data': page_data,
'mimetype': mimetypes[os.path.splitext(page_filename)[1]], 'mimetype': mimetype,
'etag': str(zip_info.CRC) 'etag': str(zip_info.CRC)
} }