From 8750f266d8831c520f142268e55c120df51e14eb Mon Sep 17 00:00:00 2001 From: Julian Rother <julian@cccv.de> Date: Sun, 5 Mar 2023 04:11:39 +0100 Subject: [PATCH] Add uncached server-side thumbnails --- warehouse/__init__.py | 12 +++++++++++- warehouse/models.py | 6 ++++++ warehouse/templates/item/list.html | 2 +- warehouse/templates/item/view.html | 2 +- warehouse/utils/__init__.py | 11 ++++++++++- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/warehouse/__init__.py b/warehouse/__init__.py index 211efbd..e02dcc4 100644 --- a/warehouse/__init__.py +++ b/warehouse/__init__.py @@ -6,7 +6,7 @@ from flask import Flask, render_template, request, redirect, url_for, Response, from requests_oauthlib import OAuth2Session from .models import db, Item, Location, Photo -from .utils import render_pdf, print_pdf, qrcode_svg, render_markdown +from .utils import render_pdf, print_pdf, qrcode_svg, render_markdown, send_thumbnail app = Flask(__name__, instance_relative_config=True) app.config.from_pyfile('config.cfg') @@ -183,6 +183,16 @@ def item_locate(item_id): def photo_show(photo_id): return Photo.query.get_or_404(photo_id).send() +@app.route('/photos/<int:photo_id>/small') +def photo_small(photo_id): + photo = Photo.query.get_or_404(photo_id) + return send_thumbnail(photo.image, 130, 100) + +@app.route('/photos/<int:photo_id>/medium') +def photo_medium(photo_id): + photo = Photo.query.get_or_404(photo_id) + return send_thumbnail(photo.image, 390, 300) + @app.route('/C/<code>') @app.route('/c/<code>') def qrcode_url(code): diff --git a/warehouse/models.py b/warehouse/models.py index 866bacc..5803213 100644 --- a/warehouse/models.py +++ b/warehouse/models.py @@ -3,6 +3,7 @@ import os from flask import current_app, send_file from flask_sqlalchemy import SQLAlchemy +from PIL import Image db = SQLAlchemy() @@ -41,6 +42,11 @@ class Photo(db.Model): path = os.path.join(current_app.config['UPLOAD_FOLDER'], self.path) return send_file(path, mimetype=self.mimetype) + @property + def image(self): + path = os.path.join(current_app.config['UPLOAD_FOLDER'], self.path) + return Image.open(path, formats=['JPEG']) + def token_typable(): alphabet = '23456789ABCDEFGHJKLMNPQRSTUVWX' # not '01OIYZ' return ''.join([secrets.choice(alphabet) for _ in range(5)]) diff --git a/warehouse/templates/item/list.html b/warehouse/templates/item/list.html index 2df46a6..985e503 100644 --- a/warehouse/templates/item/list.html +++ b/warehouse/templates/item/list.html @@ -24,7 +24,7 @@ <td style="width: 140px;"> {% if item.photos %} <a href="{{ url_for('item_view', item_id=item.id) }}" style="width: 130px; height: 100px;" class="d-flex align-items-center justify-content-center border text-bg-light"> - <img src="{{ url_for('photo_show', photo_id=(item.photos|first).id) }}" style="max-width: 100%; max-height: 100%;"> + <img src="{{ url_for('photo_small', photo_id=(item.photos|first).id) }}" style="max-width: 100%; max-height: 100%;"> </a> {% endif %} </td> diff --git a/warehouse/templates/item/view.html b/warehouse/templates/item/view.html index ce0d961..7e6905d 100644 --- a/warehouse/templates/item/view.html +++ b/warehouse/templates/item/view.html @@ -39,7 +39,7 @@ {% for photo in item.photos %} <div class="carousel-item {{ 'active' if loop.first }}" style="width: 100%; height: 100%;"> <a href="{{ url_for('photo_show', photo_id=photo.id) }}" style="width: 100%; height: 100%;" class="d-flex align-items-center justify-content-center"> - <img src="{{ url_for('photo_show', photo_id=photo.id) }}" style="max-width: 100%; max-height: 100%;"> + <img src="{{ url_for('photo_medium', photo_id=photo.id) }}" style="max-width: 100%; max-height: 100%;"> </a> </div> {% endfor %} diff --git a/warehouse/utils/__init__.py b/warehouse/utils/__init__.py index 1fbb582..676a459 100644 --- a/warehouse/utils/__init__.py +++ b/warehouse/utils/__init__.py @@ -2,7 +2,8 @@ from .pdf import render_pdf from .ipp import print_pdf from .codes import qrcode_svg -from flask import Markup +import io +from flask import Markup, send_file import markdown import bleach @@ -16,3 +17,11 @@ def render_markdown(text, short=False): result = result.split('<p>', 1)[-1] result = result.split('</p>', 1)[0] return Markup(result) + +def send_thumbnail(img, max_width, max_height): + scale = min(max_width/img.width, max_height/img.height) + img.thumbnail((int(img.width*scale), int(img.height*scale))) + buf = io.BytesIO() + img.save(buf, format='JPEG', quality=70) + buf.seek(0) + return send_file(buf, mimetype='image/jpeg') -- GitLab