【问题标题】:Django Pillow, save image as jpeg does not seem to workDjango Pillow,将图像另存为 jpeg 似乎不起作用
【发布时间】:2019-03-17 09:49:54
【问题描述】:

早安,

我正在使用 Pillow 在名为 Post 的 Django 模型中调整和保存图像的大小。图片是从imagefield中取出来的,get一下是不是RGB的,如果不是就转成RGB。

最后,我从原始图像创建一个缩略图并尝试将其保存在 MEDIA_ROOT 中。

即使图像已上传,它似乎也没有将图像转换为 jpeg。

我按照Django 2+ edit images with Pillow 此处的教程进行操作,并且正在努力满足我的需求。

我在这里错过了什么?

models.py

import os

from django.core.validators import RegexValidator
from django.db import models
from django.utils import timezone
from PIL import Image
from django.conf import settings
from django.db.models.signals import post_save
class Post(models.Model):

# Custom validators
title_validator_specialchar = RegexValidator(regex=r'^[\s*\d*a-zA-Z]{5,60}$', message="The title can't contain any special characters")

category = models.ForeignKey('Category',default=1, on_delete=models.SET_NULL, null=True)
type = models.CharField(max_length=20)
title = models.CharField(max_length=200, validators=[title_validator_specialchar])
content = models.TextField(max_length=2000)
image = models.ImageField(upload_to='%Y/%m/%d/', blank=True)
created_at = models.DateTimeField(editable=False)
updated_at = models.DateTimeField(default=timezone.now)

def save(self, *args, **kwargs):
    #On save, update timestamp date created
    if not self.id:
        self.created_at = timezone.now()
    self.updated_at = timezone.now()
    return super(Post, self).save(*args, **kwargs)

def __str__(self):
    return self.title


def resize_image(instance, **kwargs):

if instance.image:

    # we are opening image with Pillow
    img = Image.open(instance.image)

    # convert image to RGB
    if img.mode not in ('L', 'RGB'):
        img = img.convert('RGB')

    # img.size is tuple with values (width, height)
    if img.size[0] > 320 or img.size[1] > 640:
        
        # Using thumbnail to resize image but keep aspect ratio
        img.thumbnail((320, 640), Image.ANTIALIAS)
        
        # saving to original place
        # instance.image.name is in %Y/%m/%d/<name> format
        output = os.path.join(settings.MEDIA_ROOT, instance.image.name)
        img.save(output, "JPEG")

# Connect the signal with our model
post_save.connect(resize_image, Post)

【问题讨论】:

    标签: django forms image upload python-imaging-library


    【解决方案1】:

    信号处理程序接收发送者作为第一个参数,在post_save 信号的情况下是模型类,而不是模型实例。

    所以resize_image() 的参数instance 应该命名为sender 并且不包含您想要的内容。以下是获取实际实例的方法:

    def resize_image(sender, **kwargs):
        instance = kwargs.get('instance')
        if instance and instance.image:
            ...
    

    【讨论】:

    • Daniel,感谢您的解释,我应该阅读更多关于一般信号的信息。然而这并没有解决我的问题。由于我必须找到解决方案,我添加了 django-imagekit 并使用了 ProcessedImageField
    【解决方案2】:

    由于我找不到让它工作所需的东西,我决定使用 django-imagekit。

    我在我的模型上使用 ProcessedImageField 和 ResizeToFill 处理器;

    models.py

    image = ProcessedImageField(upload_to='%Y/%m/%d/', processors=[ResizeToFill(384, 216)], format='JPEG', options={'quality': 60}, blank=True)
    

    【讨论】:

      【解决方案3】:

      发生这种情况是因为您明确调用 img 以保存在 mediaroot 中,但 instance.image 保持静止。所以 django 也会保存该图像。所以我认为你必须改变 instance.image 属性而不是调用 img 来保存。为此,您必须使用 django InMemorUploadedFile

      import io
      from django.core.files.uploadedfile import InMemoryUploadedFile
      import sys
      
      if instance.image:
      
      # we are opening image with Pillow
      img = Image.open(instance.image)
      
      # convert image to RGB
      if img.mode not in ('L', 'RGB'):
          img = img.convert('RGB')
      
      # img.size is tuple with values (width, height)
      if img.size[0] > 320 or img.size[1] > 640:
          
          # Using thumbnail to resize image but keep aspect ratio
          img.thumbnail((320, 640), Image.ANTIALIAS)
          
          # saving to original place by changing instance.image. django will save it 
          #automatically in mediaroot
          img_io = io.BytesIO()
          img.save(img_io, "JPEG")
          instance.image = InMemoryUploadedFile(img_io, 'ImageField', 'image.jpeg', 
                          'image/jpeg',sys.getsizeof(img_io), None )
          
      
      
          
      

      我们不能将 Image 对象直接传递给 inastance.image,因为它会引发错误。 所以我们必须将 img 转换为 InMemoryUploadedFile 对象。

      【讨论】:

        猜你喜欢
        • 2019-01-30
        • 2016-04-25
        • 1970-01-01
        • 2015-10-24
        • 2013-08-07
        • 1970-01-01
        • 2011-09-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多