Django 将图像转换为 webp

问题描述 投票:0回答:3

我的 Django 项目应用程序中有上传图像的服务,我需要将所有图像转换为 webp,以优化前端对这些文件的进一步处理。

_convert_to_webp
方法草案:

# imports
from pathlib import Path

from django.core.files import temp as tempfile
from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image


# some service class
...
    def _convert_to_webp(self, f_object: InMemoryUploadedFile):
        new_file_name = str(Path(f_object._name).with_suffix('.webp'))
        
        temp_file = tempfile.NamedTemporaryFile(suffix='.temp.webp')
        # FIXME: on other OS may cause FileNotFoundError
        with open(temp_file 'wb') as f:
            for line in f_object.file.readlines():
                ... # will it works good?
        new_file = ...
        
        new_f_object = InMemoryUploadedFile(
            new_file,
            f_object.field_name,
            new_file_name,
            f_object.content_type,
            f_object.size,
            f_object.charset,
            f_object.content_type_extra
        )
        
        return new_file_name, new_f_object
...

f_object
是来自 POST 请求正文的
InMemoryUploadedFile
实例(Django 自动创建它)。

我的想法是创建一个临时文件,将数据从

f_object.file.readlines()
写入其中,用
PIL.Image.open
打开该文件并用
format="webp"
保存。这个想法是好的还是有另一种方法来进行文件转换?

python django python-imaging-library webp
3个回答
5
投票

我找到了一种非常干净的方法来使用 django-resized 包来做到这一点。

pip 安装后,我只需要把

imageField
换成
ResizedImageField

    img = ResizedImageField(force_format="WEBP", quality=75, upload_to="post_imgs/")

所有上传的图片都会自动转换为.webp!


1
投票

解决方案非常简单。

PIL.Image
可以使用文件实例打开,所以我只是使用
f_object.file
打开它,然后将其保存在经过优化和压缩的BytesIO实例中。

正确工作的代码:

# imports
from pathlib import Path

from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image


# some service class
...
    def _convert_to_webp(self, f_object: InMemoryUploadedFile):
        suffix = Path(f_object._name).suffix
        if suffix == ".webp":
            return f_object._name, f_object
        
        new_file_name = str(Path(f_object._name).with_suffix('.webp'))
        image = Image.open(f_object.file)
        thumb_io = io.BytesIO()
        image.save(thumb_io, 'webp', optimize=True, quality=95)
    
        new_f_object = InMemoryUploadedFile(
            thumb_io,
            f_object.field_name,
            new_file_name,
            f_object.content_type,
            f_object.size,
            f_object.charset,
            f_object.content_type_extra
        )
        
        return new_file_name, new_f_object
选择

95%
作为平衡参数。
quality=80
quality=90
的质量非常差。


0
投票

我刚刚添加了以下参数,以便更轻松地使用其他格式

 media_path = ResizedImageField(
        other_formats=['pdf'], #NEW ARGUMENT
        upload_to=document_upload_to,
        null=True,
        blank=True,
        quality=75,
        force_format='WEBP',
    )

以下文件的 ResizedImageFieldFile 类中的更新

venv/lib/python3.10/site-packages/django_resized/forms.py

class ResizedImageFieldFile(ImageField.attr_class):

    def save(self, name, content, save=True):
        #NEW LINES

        if content.name.lower().endswith(tuple(self.field.other_formats)):
            super().save(name, content, save)
            return

        #NEW LINES END

文件的 ResizedImageField 类中的更新

venv/lib/python3.10/site-packages/django_resized/forms.py

class ResizedImageField(ImageField):

    attr_class = ResizedImageFieldFile

    #ADDED other_formats IN THE INIT METHOD

    def __init__(self, verbose_name=None, name=None,other_formats=[], **kwargs):
        # migrate from 0.2.x
        for argname in ('max_width', 'max_height', 'use_thumbnail_aspect_ratio', 'background_color'):
            if argname in kwargs:
                warnings.warn(
                    f'Error: Keyword argument {argname} is deprecated for ResizedImageField, '
                    'see README https://github.com/un1t/django-resized',
                    DeprecationWarning,
                )
                del kwargs[argname]
        self.other_formats = other_formats #NEW LINE
© www.soinside.com 2019 - 2024. All rights reserved.