Django 在保存前调整图像大小

Django Resize Image Before Saving

目标:将调整大小的图像(具有相同的文件名和纵横比)上传到 AWS S3。

问题:目前在保存时上传的是原始图片,而不是调整后的图片。

我试过什么?:我尝试了多种不同的方法来完成这个,但我 运行 遇到了各种问题,例如宽高比不正确,质量差图像质量(使用 django-resize 时)等。下面的代码看起来非常接近,但我似乎无法找到哪里出错了。

models.py

class Profile(BaseModel):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')


    def save(self, commit=True, *args, **kwargs): #Edited

        if commit:
            img = Image.open(self.image)

            if img.height > 300 or img.width > 300:
                output_size = (300, 300)
                img.thumbnail(output_size)
                img.save(self.image.name, optimize=True, quality=100)

            super().save()

解法:

经过很长一段时间我终于在这个blog中找到了答案。

最后我在users/utils.py文件中新建了一个函数:

from django.core.files import File
from pathlib import Path
from PIL import Image
from io import BytesIO

image_types = {
    "jpg": "JPEG",
    "jpeg": "JPEG",
    "png": "PNG",
    "gif": "GIF",
    "tif": "TIFF",
    "tiff": "TIFF",
}

def image_resize(image, width, height):
    # Open the image using Pillow
    img = Image.open(image)
    # check if either the width or height is greater than the max
    if img.width > width or img.height > height:
        output_size = (width, height)
        # Create a new resized “thumbnail” version of the image with Pillow
        img.thumbnail(output_size)
        # Find the file name of the image
        img_filename = Path(image.file.name).name
        # Spilt the filename on “.” to get the file extension only
        img_suffix = Path(image.file.name).name.split(".")[-1]
        # Use the file extension to determine the file type from the image_types dictionary
        img_format = image_types[img_suffix]
        # Save the resized image into the buffer, noting the correct file type
        buffer = BytesIO()
        img.save(buffer, format=img_format)
        # Wrap the buffer in File object
        file_object = File(buffer)
        # Save the new resized file as usual, which will save to S3 using django-storages
        image.save(img_filename, file_object)

然后覆盖models.py中的save()函数:

models.py

from users.utils import image_resize

class Profile(BaseModel):
    #some other fields
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')
    

    def save(self, commit=True, *args, **kwargs):

        if commit:
            image_resize(self.image, 250, 250)
            super().save(*args, **kwargs)