我正在使用 django-stdimage 创建图像的变体。
class Photo(models.Model):
photo = StdImageField(upload_to='photos', verbose_name=_("photo"),
variations={'large': (600, 600), 'thumbnail': (100, 100)}
StdImageField 对图像进行自己的操作,子类化 ImageField 并具有 attr_class = StdImageFieldFile
StdImageFieldFile 执行实际的保存操作
class StdImageFieldFile(ImageFieldFile):
"""
Like ImageFieldFile but handles variations.
"""
def save(self, name, content, save=True):
super(StdImageFieldFile, self).save(name, content, save)
render_variations = self.field.render_variations
if callable(render_variations):
render_variations = render_variations(
file_name=self.name,
variations=self.field.variations,
storage=self.storage,
)
if not isinstance(render_variations, bool):
msg = (
'"render_variations" callable expects a boolean return value,'
' but got %s'
) % type(render_variations)
raise TypeError(msg)
if render_variations:
self.render_variations()
但是,我想在 StdImageFieldFile 执行操作(旋转)之前对图像进行一些操作。
所以我创建了我的自定义字段,以便在将图像传递给 stdimage 之前捕获图像
class Rotate(ImageFieldFile):
def save(self, name, content, save=True):
save = False
return super(Rotate, self).save(name, content, save)
class StdImageFieldFileRotateMixin(Rotate, StdImageFieldFile):
pass
class StdImageFieldRotate(StdImageField):
attr_class = StdImageFieldFileRotateMixin
我在 Rotate 类的 content 属性中有图像,我可以使用 PIL 操作图像,但完成后,我不知道如何将此图像分配回内容属性。它似乎是在较低级别生成的。是否有一种方法可以生成此 content 属性,然后 MRO 将处理其余部分(即将其传递给 StdImageFieldFile,它将完成其余部分)?
请您参考如下方法:
您可以将可调用对象传递给 StdImageField 类的参数 render_variations 并在那里预处理图像。
例如,假设您想要节省磁盘空间并将原始图像的大小调整为较小的版本,只将较小的图像与 django-stdimage 创建的变体一起使用。你可以这样写一个函数:
from io import BytesIO
from PIL import Image
from django.core.files.base import ContentFile
from stdimage.utils import render_variations
def preprocess(file_name, variations, storage):
with storage.open(file_name) as f:
with Image.open(f) as image:
file_format = image.format
# resize to a maximum of 1000x1000 keeping aspect ratio
image.thumbnail((1000, 1000), resample=Image.ANTIALIAS)
with BytesIO() as file_buffer:
image.save(file_buffer, file_format)
f = ContentFile(file_buffer.getvalue())
# delete the original big image
storage.delete(file_name)
# save the resized version with the same filename and format
storage.save(file_name, f)
# render stdimage variations
render_variations(file_name, variations, replace=True, storage=storage)
return False # prevent default rendering
然后您可以将该函数传递给 StdImageField 类的 render_variations 参数,如下所示:
class Photo(models.Model):
photo = StdImageField(upload_to='photos', verbose_name=_("photo"),
variations={'large': (600, 600), 'thumbnail': (100, 100)},
render_variations=preprocess)
这项技术的灵感来自 Async image processing example在 Github 上的 django-stdimage 项目的自述文件中。
preprocess 函数中处理图像的方式也受到 stdimage.models.StdImageFieldFile.render_variation 的启发。方法并使用 Django 存储对象来处理图像文件的不同存储类型(想想 Amazon S3)。
