Django在被stdimage處理之前修改圖像

[英]Django modify image before it's handled by stdimage


I'm using django-stdimage for creating variations of the image.

我使用django-stdimage創建圖像的變化。

class Photo(models.Model):
    photo = StdImageField(upload_to='photos', verbose_name=_("photo"),
                      variations={'large': (600, 600), 'thumbnail': (100, 100)}

StdImageField does it's own operations on the image, subclassing ImageField and having attr_class = StdImageFieldFile

StdImageField對圖像進行自己的操作,子類化ImageField,並具有attr_class = StdImageFieldFile

StdImageFieldFile does the actual save operation

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()

However, I want to do some manipulation of the image before StdImageFieldFile does it (rotating).

但是,我想在StdImageFieldFile執行之前對圖像進行一些操作(旋轉)。

So I created my custom field, to catch the image before it's passed to stdimage

所以我創建了我的自定義字段,以便在圖像傳遞給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

I have the image in the content property of the Rotate class and I can manipulate the image using PIL, but after it's done, I don't know how to assign this image back to the content property. It seems that it's generated on the lower level. Is there a method to generate this content property and then MRO will handle the rest (i.e. pass it to StdImageFieldFile and it will do the rest)?

我在Rotate類的content屬性中有這個圖像,我可以使用PIL來操作這個圖像,但是完成之后,我不知道如何將這個圖像分配回content屬性。它似乎是在較低的水平上產生的。是否有一種方法來生成這個內容屬性,然后MRO將處理其余的(例如,將它傳遞給StdImageFieldFile,它將處理其余的)?

1 个解决方案

#1


1  

You can pass a callable to the argument render_variations of the StdImageField class and pre-process the image there.

您可以將可調用性傳遞給StdImageField類的參數render_variation,並在那里對映像進行預處理。

For example assume you want to save disk space and resize the original image to a smaller version, taking only the smaller image together with variations created by django-stdimage. You can write a function like this:

例如,假設您希望節省磁盤空間,並將原始映像調整為更小的版本,只使用較小的映像和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

You can then pass the function to the render_variations argument of the StdImageField class, like this:

然后,您可以將函數傳遞給StdImageField類的render_changes參數,如下所示:

class Photo(models.Model):
    photo = StdImageField(upload_to='photos', verbose_name=_("photo"),
                  variations={'large': (600, 600), 'thumbnail': (100, 100)},
                  render_variations=preprocess)

This technique is inspired from the Async image processing example in the README of the django-stdimage project on Github.

這種技術的靈感來自Github上的django-stdimage項目中的異步圖像處理示例。

Also the way in which the image is handled in the preprocess function is inspired from the stdimage.models.StdImageFieldFile.render_variation method and uses Django Storage objects to deal with different storage types for image files (think Amazon S3).

在預處理函數中處理圖像的方式也是從stdimage.model . stdimagefieldfile中獲得的。render_change方法並使用Django存儲對象來處理圖像文件的不同存儲類型(如Amazon S3)。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2015/09/25/7205d3cc783031ccbe127d54b7d35346.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com