F(backend): add public media derivatives pipeline
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from core.models import BaseModel
|
||||
from core.media import (
|
||||
delete_image_derivatives_by_name,
|
||||
get_image_previous_name,
|
||||
safe_process_public_image,
|
||||
)
|
||||
|
||||
|
||||
MAX_IMAGE_FILE_SIZE_BYTES = 2 * 1024 * 1024
|
||||
|
||||
class Gallery(BaseModel):
|
||||
title = models.CharField(max_length=200)
|
||||
description = models.TextField(blank=True)
|
||||
@@ -27,47 +28,39 @@ class Gallery(BaseModel):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
previous_image_name = get_image_previous_name(self, "image")
|
||||
current_image_name = self.image.name if self.image else None
|
||||
image_changed = previous_image_name != current_image_name
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
if self.image:
|
||||
# Get file size
|
||||
self.file_size = self.image.size
|
||||
|
||||
# Get image dimensions
|
||||
with Image.open(self.image.path) as img:
|
||||
self.width, self.height = img.size
|
||||
|
||||
# Compress image if it's too large
|
||||
self.compress_image()
|
||||
|
||||
# Update fields without triggering save again
|
||||
Gallery.objects.filter(pk=self.pk).update(
|
||||
file_size=self.file_size,
|
||||
width=self.width,
|
||||
height=self.height
|
||||
|
||||
if image_changed and previous_image_name:
|
||||
delete_image_derivatives_by_name(
|
||||
self.image.storage if self.image else None,
|
||||
previous_image_name,
|
||||
"gallery",
|
||||
delete_original=True,
|
||||
)
|
||||
|
||||
def compress_image(self):
|
||||
"""Compress image if it's larger than 2MB or dimensions are too large"""
|
||||
if not self.image:
|
||||
if image_changed:
|
||||
Gallery.objects.filter(pk=self.pk).update(file_size=None, width=None, height=None)
|
||||
return
|
||||
|
||||
with Image.open(self.image.path) as img:
|
||||
# Convert to RGB if necessary
|
||||
if img.mode in ("RGBA", "P"):
|
||||
img = img.convert("RGB")
|
||||
|
||||
# Resize if too large
|
||||
max_size = (1920, 1080)
|
||||
if img.size[0] > max_size[0] or img.size[1] > max_size[1]:
|
||||
img.thumbnail(max_size, Image.Resampling.LANCZOS)
|
||||
|
||||
# Compress if file size is too large
|
||||
quality = 85
|
||||
if self.file_size and self.file_size > MAX_IMAGE_FILE_SIZE_BYTES:
|
||||
quality = 70
|
||||
|
||||
img.save(self.image.path, "JPEG", quality=quality, optimize=True)
|
||||
|
||||
if getattr(self, "_defer_image_processing", False):
|
||||
return
|
||||
|
||||
if image_changed:
|
||||
result = safe_process_public_image(self.image, "gallery")
|
||||
if result:
|
||||
Gallery.objects.filter(pk=self.pk).update(
|
||||
file_size=result.file_size,
|
||||
width=result.width,
|
||||
height=result.height,
|
||||
)
|
||||
self.file_size = result.file_size
|
||||
self.width = result.width
|
||||
self.height = result.height
|
||||
|
||||
@property
|
||||
def file_size_mb(self):
|
||||
|
||||
Reference in New Issue
Block a user