cista-storage/cista/preview.py

41 lines
1.1 KiB
Python

import asyncio
import io
from pathlib import PurePosixPath
from urllib.parse import unquote
from PIL import Image
from sanic import Blueprint, raw
from sanic.exceptions import Forbidden, NotFound
from cista import config
from cista.util.filename import sanitize
bp = Blueprint("preview", url_prefix="/preview")
@bp.get("/<path:path>")
async def preview(req, path):
"""Preview a file"""
width = int(req.query_string) if req.query_string else 768
rel = PurePosixPath(sanitize(unquote(path)))
path = config.config.path / rel
if not path.is_file():
raise NotFound("File not found")
size = path.lstat().st_size
if size > 20 * 10**6:
raise Forbidden("File too large")
img = await asyncio.get_event_loop().run_in_executor(
req.app.ctx.threadexec, process_image, path, width
)
return raw(img, content_type="image/webp")
def process_image(path, maxsize):
img = Image.open(path)
w, h = img.size
img.thumbnail((min(w, maxsize), min(h, maxsize)))
# Save as webp
imgdata = io.BytesIO()
img.save(imgdata, format="webp", quality=70, method=6)
return imgdata.getvalue()