From 78f0f379fc63452452a4cf9154235853ec545968 Mon Sep 17 00:00:00 2001 From: bramval Date: Sun, 25 Jan 2026 16:54:01 +0100 Subject: [PATCH] Make image crop target size configurable --- app/__init__.py | 18 ++++++++++++++++++ app/routes/company.py | 15 +++++++++++---- app/templates/company/dashboard.html | 2 +- app/templates/company/playlist_detail.html | 17 +++++++++++++++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 2b2822a..8d43137 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -20,6 +20,24 @@ def create_app(): app.config.setdefault("SQLALCHEMY_TRACK_MODIFICATIONS", False) app.config.setdefault("UPLOAD_FOLDER", os.path.join(app.root_path, "static", "uploads")) + # Target output resolution for cropped images. + # This is used by the client-side cropper (to generate an upload) and by the server-side + # image processing (to cap the resulting WEBP size). + # + # Defaults to Full HD landscape (1920x1080). Portrait is derived by swapping. + # Override via env vars, e.g.: + # IMAGE_CROP_TARGET_W=1920 + # IMAGE_CROP_TARGET_H=1080 + def _env_int(name: str, default: int) -> int: + try: + v = int(os.environ.get(name, "") or default) + except (TypeError, ValueError): + v = default + return max(1, v) + + app.config.setdefault("IMAGE_CROP_TARGET_W", _env_int("IMAGE_CROP_TARGET_W", 1920)) + app.config.setdefault("IMAGE_CROP_TARGET_H", _env_int("IMAGE_CROP_TARGET_H", 1080)) + # NOTE: Videos should be max 250MB. # Flask's MAX_CONTENT_LENGTH applies to the full request payload (multipart includes overhead). # We set this slightly above 250MB to allow for multipart/form fields overhead, while still diff --git a/app/routes/company.py b/app/routes/company.py index 30c6069..8d417b7 100644 --- a/app/routes/company.py +++ b/app/routes/company.py @@ -147,15 +147,22 @@ def _save_compressed_image( img = img.convert("RGB") # Optional crop + # NOTE: The front-end may already upload a cropped image (canvas export), but we still + # enforce aspect + maximum output size here for consistency. + target_w = int(current_app.config.get("IMAGE_CROP_TARGET_W", 1920) or 1920) + target_h = int(current_app.config.get("IMAGE_CROP_TARGET_H", 1080) or 1080) + target_w = max(1, target_w) + target_h = max(1, target_h) + if cm == "16:9": img = _center_crop_to_aspect(img, 16, 9) - max_box = (1920, 1080) + max_box = (target_w, target_h) elif cm == "9:16": img = _center_crop_to_aspect(img, 9, 16) - max_box = (1080, 1920) + max_box = (target_h, target_w) else: - # No crop: allow both portrait and landscape up to 1920px on the longest side. - max_box = (1920, 1920) + # No crop: allow both portrait and landscape up to target_w/target_h on the longest side. + max_box = (max(target_w, target_h),) * 2 # Resize down if very large (keeps aspect ratio) img.thumbnail(max_box) diff --git a/app/templates/company/dashboard.html b/app/templates/company/dashboard.html index e8b8595..89e851a 100644 --- a/app/templates/company/dashboard.html +++ b/app/templates/company/dashboard.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% block content %} -

Welcome{% if current_user and current_user.email %}, {{ current_user.email }}{% endif %}!

+

Dashboard

diff --git a/app/templates/company/playlist_detail.html b/app/templates/company/playlist_detail.html index be1ea52..dbce5e2 100644 --- a/app/templates/company/playlist_detail.html +++ b/app/templates/company/playlist_detail.html @@ -1,5 +1,12 @@ {% extends "base.html" %} {% block content %} + {# Expose server-side crop target sizes to the JS without embedding Jinja inside JS #} +
{# Cropper.js (used for image cropping) #}