简体   繁体   English

在将图像添加到存储位置之前,如何在Django中优化图像(文件上传)?

[英]How to optimize an image (file upload) in Django before it is added to the storage location?

We are updating our backend storage for our Django project from a local disk store to an Amazon S3 bucket. 我们正在将Django项目的后端存储从本地磁盘存储更新为Amazon S3存储桶。 Currently, we add the image, then optimize it and at a later time rsync it to our CDN. 当前,我们添加图像,然后对其进行优化,然后将其重新同步到我们的CDN。 We control these steps so I just optimize after the upload and before the rsync. 我们控制了这些步骤,因此我只在上传之后和rsync之前进行优化。

We are moving to Amazon S3 and I would like to now optimize the images before they are uploaded to the S3 bucket, primarily so we don't upload to S3, then download in order to optimize and finally, re-upload. 我们正在迁移到Amazon S3,我现在想在将图像上传到S3存储桶之前对其进行优化,主要是为了避免先将图像上传到S3,然后再进行下载以进行优化,最后重新上传。 Why have three trips when we can probably do this in one. 为什么我们可以合而为一地进行三趟旅行。

My question is this: How can we intercept the upload to optimize the file before it's pushed to the storage backend, in this case, Amazon S3. 我的问题是:在将文件推送到存储后端(在本例中为Amazon S3)之前,我们如何拦截上传以优化文件。

If it helps I am using amazon's boto library and django-storages-redux. 如果有帮助,我正在使用亚马逊的boto库和django-storages-redux。


I had this question in draft form and realized I had never posted it. 我有一个草稿形式的问题,意识到我从未张贴过。 I did not find the solution on stack overflow so I thought I would add it as a Q&A post. 我没有在堆栈溢出时找到解决方案,所以我想将其添加为“问答”帖子。

The solution is to override Django's TemporaryFileUploadHandler class. 解决方案是重写Django的TemporaryFileUploadHandler类。 I also set the file size for uploads to zero so they all happen on disk and no in memory, though that might not be necessary. 我也将上传文件的大小设置为零,因此它们全部都发生在磁盘上,而不发生在内存中,尽管可能没有必要。

      # encoding: utf-8
      from image_diet import squeeze
      import shutil
      import uuid

      from django.core.files import File
      from django.core.files.uploadhandler import TemporaryFileUploadHandler


      class CompressImageUploadHandler(TemporaryFileUploadHandler):
      """
      Run image squeeze on our temporary file before upload to S3
      """

        def __init__(self, *args, **kwargs):
            self.image_types = ('image/jpeg', 'image/png')
            self.file_limit = 200000
            self.overlay_fields = (
                'attribute_name',  
            )
            self.skip_compress_fields = (
                'attribute_name',  
            )
            super(CompressImageUploadHandler, self).__init__(*args, **kwargs)

        def compress_image(self):
            """
            For image files we need to compress them, but we need to do some
            trickery along the way. We need to close the file, pass it to
            image_diet.squeeze, then reopen the file with the same file name
            """

            # if it's an image and small enough. Squeeze.
            if (self.file.size < self.file_limit and
                    self.field_name not in self.skip_compress_fields):
                # the beginning is a good place to start.
                self.file.seek(0)
                # let's squeeze this image. 
                # first, make a copy.
                file_name = self.file.name
                file_content_type = self.file.content_type
                copy_path = u"{}{}".format(
                    self.file.temporary_file_path(),
                    str(uuid.uuid4())[:8]
                )
                shutil.copyfile(
                    self.file.temporary_file_path(),
                    copy_path
                )
                # closed please. image_squeeze updates on an open file
                self.file.close()
                squeeze(copy_path)
                squeezed_file = open(copy_path)
                self.file = File(squeezed_file)
                # now reset some of the original values
                self.file.name = file_name
                self.file.content_type = file_content_type

        def screenshot_overlay(self):
            """
            Apply the guarantee_image_overlay method on screenshots
            """
            if self.field_name in self.overlay_fields:
                # this is a custom method that adds an overlay to the upload image if it's in the tuple of overlay_fields
                guarantee_image_overlay(self.file.temporary_file_path())
                # we have manipulated file, back to zero
                self.file.seek(0)

        def file_complete(self, file_size):
            """
            Return the file object, just run image_squeeze against it.
            This happens before the file object is uploaded to Amazon S3.
            While the pre_save hook happens after the Amazon upload.
            """
            self.file.seek(0)
            self.file.size = file_size

            if self.content_type in self.image_types:
                # see if we apply the screenshot overlay.
                self.screenshot_overlay()
                self.compress_image()

            return super(CompressImageUploadHandler, self).file_complete(file_size)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM