【问题标题】:How to resize source with sorl-thumbnail?如何使用 sorl-thumbnail 调整源大小?
【发布时间】:2012-03-10 09:17:22
【问题描述】:

我在网上搜索我的问题,但找不到明确的答案或任何示例。

基本上,我想使用 sorl 并希望在模型保存期间调整源图像的大小以将其调整为 640x480 大小,这样我就不会最终将用户的原始 2.5 MB 文件存储在磁盘上。然后,我将使用模板标签从我的源文件中创建常规缩略图,如 sorl 中所述。

我遇到了几个来源,指的是使用应该在 sorl.thumbnail.fields 中可用的 ThumbnailField 模型字段。请参阅链接here。但是,在我从树干获取的最新 sorl 副本中,我没有看到任何 ThumbnailField 或 ImageWithThumbnailsField。我尝试在模型中导入它相应地失败了。虽然我看到这些参考资料很旧,但我想知道我是否可以使用最新的 sorl 实现同样的效果。

另一方面,sorl 文档仅指出来自 sorl.thumbnail 的 ImageField(请参阅 here)没有任何大小参数来控制源调整大小。

顺便说一句,我看到easy_thumbnail提供了这个功能,它采用输入参数source_resize。

任何帮助将不胜感激!

摘要

我接受了以下答案,但是我觉得对这个用例的自然 sorl 支持可能非常有用 - 即将 resize_source 参数添加到 sorl 的 ImageField 以允许调整源图像的大小。以下是这在该领域有用的两个因素:

  1. 如果您的应用不需要,不要存储用户的巨大原始图像。节省磁盘空间。

  2. 如果您没有特定的极高质量原因,则不要花费额外的 CPU 来调整来自巨大源图像的缩略图大小。为了避免这种情况,可能会在模板中编写嵌套标签以从较小尺寸的图像中获取缩略图,但它很快就会变得烦人。

【问题讨论】:

  • 所以您希望用户上传的图片在应用任何缩略图裁剪之前调整到可管理的宽度和高度?
  • 是的,基本上我想将源文件始终保存在磁盘上以适应 640x480 的盒子。
  • 我感觉 get_thumbnail 会帮助我做到这一点 - example here。但是,我希望有人确认这是唯一的情况,并建议在 ModelForm 保存期间如何最好地实现这一点。例如,我应该使用预创建信号或类似信号来实现这一点吗??

标签: django thumbnails image-resizing sorl-thumbnail


【解决方案1】:

以下代码使用 PIL 引擎(sorl-thumbnail 的一部分)裁剪名为 picture.jpg 的图像(使用 Python 3.8sorl-thumbnail==12.6.3 测试):

#
# Change this import to get the Engine of your underlying libraries.
# Options are: convert_engine, pgmagick_engine, pil_engine, vipsthumbnail_engine or wand_engine.
#
from sorl.thumbnail.engines.pil_engine import Engine

# This object has all we need
engine = Engine()

#
# When receiving data from a request
# you probably have a BytesIO instance ready to use like:
#
#   im = engine.get_image(my_bytes_io)
#
with open("picture.jpg", "rb") as f:
    im = engine.get_image(f)

im_crop = engine.crop(im, (535, 535), options={'crop': 'smart'})

im_crop.save("picture-thumb.jpg")

我不会修改save 方法,而是有一个帮助函数来减小图像大小(使用上面的行),并在更新图像字段之前从 Django 视图或表单中调用它。虽然它可以在 save 本身上运行。

另一方面,Engine API 有更多有用的功能,可能会有用!这个 API 自第一次提交以来就一直存在,所以在我看来,它在未来不太可能改变:createcropboxorientationflip_dimensionscolorspaceremove_bordercalculate_scaling_factor ,scale,crop,rounded,blur,padding,write,cleanup,get_image_ratio,get_image_info,get_image_size,get_image_size,get_image_size,@9876 /p>

【讨论】:

    【解决方案2】:

    我在上面的代码中发现了一个缺陷,如果有人想使用它,就会得到“str has no method chunk()”。这是我的解决方法:

        from sorl.thumbnail import get_thumbnail
        from django.core.files.base import ContentFile
    
     class Foo(models.Model):
        image = models.ImageField(upload_to...)
    
    
        def save(self, *args, **kwargs):
            if not self.id:  
                super(Foo, self).save(*args, **kwargs)  
                resized = get_thumbnail(self.image, "100x100" ...)
                self.image.save(resized.name, ContentFile(resized.read()), True)
            super(Foo, self).save(*args, **kwargs)
    

    【讨论】:

      【解决方案3】:

      我一直在寻找解决方案,最终写了应用程序django-resized

      【讨论】:

        【解决方案4】:

        您提到的 Sorl 的 ImageField 只是一个普通的 Django ImageField,具有管理缓存缩略图删除的额外好处。初始上传时没有调整大小 - 这是您必须通过您用于上传的视图手动实现的东西。 The docs show how to go about this。您可以使用 sorl in 该视图本身进行实际的调整大小操作,使用 low level API examlpes

        编辑

        一种更快的替代方法是在使用 sorl 保存模型时调整图像大小。您可以执行以下操作(尽管完全未经测试!)

        from sorl.thumbnail import get_thumbnail
        
        class Foo(models.Model):
            image = models.ImageField(upload_to...)
        
            def save(self, *args, **kwargs):
                if not self.id:
                    # Have to save the image (and imagefield) first
                    super(Foo, self).save(*args, **kwargs)
                    # obj is being created for the first time - resize
                    resized = get_thumbnail(self.image, "100x100" ...)
                    # Manually reassign the resized image to the image field
                    self.image.save(resized.name, resized.read(), True)
                super(Foo, self).save(*args, **kwargs)
        

        这意味着您将在磁盘上拥有相同图像的 2 个版本 - 一个是 django 图像字段决定保存它(upload_to 路径),另一个是 sorl thumbnail 保存了调整大小的缩略图。这与图像被上传和保存两次的事实一起,是这种方法的缺点。不过实现起来更快

        【讨论】:

        • 感谢您的回答!你能详细说明一下链接吗?我很想知道推荐的方法是什么。如果在视图中我应该保存我的模型两次 - 最初通过 ModelForm 保存一次,然后在实例图像字段上应用低级方法后再次将实例保存在视图中?
        • 理想情况下您只需要保存一次 - 您实际上是在保存文件之前调整文件大小,而不是保存、调整大小并再次保存。这就是handle_uploaded_file 方法派上用场的地方——这是将实际文件保存到磁盘上的地方。稍后我会尝试添加一个示例
        • 是的,很明显,我唯一想知道的是自己处理上传是否会影响以后移动到另一个存储(比如 S3)?这是唯一让我想知道是自己处理还是让 ImageField 解决它并保存实例然后更新它的部分(尽管如果一切都在 S3 上,从性能的角度来看这也有点难看)。跨度>
        • pastylegs 感谢您提供详细的示例!我想知道在您的示例中将文件从 get_thumbnail 目标移动到我的 upload_to 目标然后简单地将路径分配给 self.image 之前保存会更好吗?它会消除我认为的第二次保存......你怎么看?
        • 是的,但是 sorl thumbnail 将在缓存中有一个条目指向一个不存在的文件(您已移动)。您可能永远不会请求该文件(要求与原始文件大小相同的缩略图会很奇怪)但这仍然不是一个好习惯
        猜你喜欢
        • 1970-01-01
        • 2011-06-10
        • 2015-01-16
        • 1970-01-01
        • 2011-07-31
        • 1970-01-01
        • 2012-06-21
        • 2013-01-30
        • 2015-06-28
        相关资源
        最近更新 更多