Some refactoring, and added a script to regenerate variants

This commit is contained in:
2025-05-03 13:19:12 +02:00
parent 51869549f3
commit 444c8ceb62
7 changed files with 176 additions and 36 deletions

View File

@@ -0,0 +1,55 @@
from django.core.management.base import BaseCommand
from images.models import ImageVariant
from images.utils import get_b2_resource
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument("variants", nargs="+", type=str)
def handle(self, *args, **options):
if options["variants"] and len(options["variants"]) > 0:
variants = options["variants"]
else:
variants = ImageVariant.objects.all()
bucket = get_b2_resource()
for variant_id in variants:
print("Regenerating variant %s" % variant_id)
image_variant = ImageVariant.objects.filter(id=variant_id).first()
if image_variant.is_full_size and (
image_variant.file_type == "jpg" or image_variant.file_type == "png"
):
print("Can't regenerate original image")
continue
if image_variant.file_type == "webp" or image_variant.file_type == "avif":
image_variant.regenerate = True
image_variant.save()
continue
image, file_extension = image_variant.image.create_resized_image(
image_variant.height,
image_variant.width,
image_variant.gaussian_blur,
image_variant.brightness,
)
if file_extension == "jpg":
content_type = "image/jpeg"
elif file_extension == "png":
content_type = "image/png"
else:
content_type = "binary/octet-stream"
image_variant.file_type = file_extension
bucket.upload_fileobj(
image,
image_variant.backblaze_filepath,
ExtraArgs={"ContentType": content_type},
)

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2 on 2025-05-03 10:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("images", "0007_image_version_imagevariant_available_and_more"),
]
operations = [
migrations.AddField(
model_name="imagevariant",
name="regenerate",
field=models.BooleanField(default=False),
),
]

View File

@@ -58,18 +58,7 @@ class Image(models.Model):
available=False,
).save()
ImageVariant(
image=variant.image,
height=variant.height,
width=variant.width,
is_full_size=variant.is_full_size,
file_type="jpegli",
gaussian_blur=variant.gaussian_blur,
brightness=variant.brightness,
available=False,
).save()
def create_variant(self, width, height, gaussian_blur, brightness):
def download_original_variant(self):
bucket = get_b2_resource()
original_image = BytesIO()
@@ -85,8 +74,46 @@ class Image(models.Model):
original_image,
)
original_image.seek(0)
return original_image
def create_resized_image(
self,
height,
width,
gaussian_blur,
brightness,
):
original_image = self.download_original_variant()
resized_image = BytesIO()
file_extension = "jpg"
with PILImage.open(original_image) as im:
ImageOps.exif_transpose(im, in_place=True)
im = im.filter(ImageFilter.GaussianBlur(gaussian_blur))
enhancer = ImageEnhance.Brightness(im)
im = enhancer.enhance(brightness)
im.thumbnail(
(width, height), resample=PILImage.Resampling.LANCZOS, reducing_gap=3.0
)
if im.has_transparency_data:
try:
im.save(resized_image, "PNG", quality=90)
file_extension = "png"
except OSError:
im.convert("RGB").save(resized_image, "JPEG", quality=90)
else:
try:
im.save(resized_image, "JPEG", quality=90)
except OSError:
im.convert("RGB").save(resized_image, "JPEG", quality=90)
resized_image.seek(0)
return resized_image, file_extension
def create_variant(self, width, height, gaussian_blur, brightness):
bucket = get_b2_resource()
image_variant = ImageVariant(
image=self,
@@ -99,29 +126,18 @@ class Image(models.Model):
available=True,
)
content_type = "image/jpeg"
resized_image, file_extension = self.create_resized_image(
height, width, gaussian_blur, brightness
)
with PILImage.open(original_image) as im:
ImageOps.exif_transpose(im, in_place=True)
im = im.filter(ImageFilter.GaussianBlur(gaussian_blur))
enhancer = ImageEnhance.Brightness(im)
im = enhancer.enhance(brightness)
im.thumbnail((width, height))
if file_extension == "jpg":
content_type = "image/jpeg"
elif file_extension == "png":
content_type = "image/png"
else:
content_type = "binary/octet-stream"
if im.has_transparency_data:
try:
im.save(resized_image, "PNG")
image_variant.file_extension = "png"
content_type = "image/png"
except OSError:
im.convert("RGB").save(resized_image, "JPEG")
else:
try:
im.save(resized_image, "JPEG")
except OSError:
im.convert("RGB").save(resized_image, "JPEG")
resized_image.seek(0)
image_variant.file_type = file_extension
bucket.upload_fileobj(
resized_image,
@@ -146,6 +162,7 @@ class ImageVariant(models.Model):
is_full_size = models.BooleanField(default=False)
file_type = models.CharField(max_length=10)
available = models.BooleanField(default=False)
regenerate = models.BooleanField(default=False)
@property
def backblaze_filepath(self):