Django - изменение размера изображения и создание эскиза на лету в методе сохранения с использованием PIL - PullRequest
1 голос
/ 15 апреля 2019

Мне нужно было изменить размеры изображений и создать миниатюры в моем приложении django 2.1.7 . Я решил сделать это через PIL перезаписанным методом SAVE.

У меня есть 2 версии моего кода, одна полностью работает, а другая - нет. Проблема в том, что я действительно не понимаю, что происходит, потому что я бы сказал, что обе версии должны работать. Так может кто-нибудь объяснить мне, где проблема в коде ниже:

#models.py
#I am getting error OSError: cannot identify image file <_io.BytesIO object at 0x105a10200>

from django.db import models
import os
import PIL
from PIL import Image
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile

 class Photo(models.Model):
    image = models.ImageField(upload_to=change_image_name, null=True, blank=True, help_text = "")
    thumb = models.ImageField(upload_to=change_thumb_name, null=True, blank=True, help_text = "")
    gallery = models.ForeignKey(PhotoGallery, on_delete=models.CASCADE, related_name='image')



def save(self, *args, **kwargs):        
    maxsize = (1920, 1080) # max_size for image
    th_maxsize = (1000,1000) #ma_size for thubnail
    width,height = get_image_dimensions(self.image) 

    with Image.open(BytesIO(self.image.read())) as thumb:        
        if width > 1000:
            print ('image for thumb wider then 1000, doing resize')
            new_thumb = thumb.thumbnail(th_maxsize, PIL.Image.ANTIALIAS)
            output_1000 = BytesIO()
            thumb.save(output_1000, format='JPEG', quality=90)
            output_1000.seek(0)
            new_size = len(output_1000.getvalue())
            self.thumb = InMemoryUploadedFile(file=output_1000, field_name='ImageField', name="%s.jpg" % self.image.name.split('.')[0], content_type='image/jpeg', size=new_size, charset=None)
        else:
            print ('saving thumbnail, no resize')
            output_thumb = BytesIO()
            thumb.save(output_thumb, format='JPEG', quality='keep')
            output_thumb.seek(0)
            new_size = len(output_thumb.getvalue())
            self.thumb = InMemoryUploadedFile(file=output_thumb, field_name='ImageField', name="%s.jpg" % self.image.name.split('.')[0], content_type='image/jpeg', size=new_size, charset=None)

   if width > 1920:            
        with Image.open(BytesIO(self.image.read())) as img: #error appear here
            print ('image wider then 1920, doing resize')
            new_image = img.thumbnail(maxsize, PIL.Image.ANTIALIAS)
            output = BytesIO()
            img.save(output, format='JPEG', quality=90)
            output.seek(0)
            new_size = len(output.getvalue())
            self.image = InMemoryUploadedFile(file=output, field_name='ImageField', name="%s.jpg" % self.image.name.split('.')[0], content_type='image/jpeg', size=new_size, charset=None)             
    super(Photo, self).save(*args, **kwargs)

И, наконец, вот код, в который я только переместил деталь с условием

если ширина> 1920

наверх. Этот код работает отлично, я не понимаю, почему первый нет. Может кто-нибудь объяснить, что здесь происходит.

def save(self, *args, **kwargs):        
    maxsize = (1920, 1080) # max_size for image
    th_maxsize = (1000,1000) #ma_size for thubnail
    width,height = get_image_dimensions(self.image)

    if width > 1920:
        with Image.open(BytesIO(self.image.read())) as img:
            print ('image wider then 1920, doing resize')
            new_image = img.thumbnail(maxsize, PIL.Image.ANTIALIAS)
            output = BytesIO()
            img.save(output, format='JPEG', quality=90)
            output.seek(0)
            new_size = len(output.getvalue())
            self.image = InMemoryUploadedFile(file=output, field_name='ImageField', name="%s.jpg" % self.image.name.split('.')[0], content_type='image/jpeg', size=new_size, charset=None)        

    with Image.open(BytesIO(self.image.read())) as thumb:        
        if width > 1000:
            print ('image for thumb wider then 1000, doing resize')
            new_thumb = thumb.thumbnail(th_maxsize, PIL.Image.ANTIALIAS)
            output_1000 = BytesIO()
            thumb.save(output_1000, format='JPEG', quality=90)
            output_1000.seek(0)
            new_size = len(output_1000.getvalue())
            self.thumb = InMemoryUploadedFile(file=output_1000, field_name='ImageField', name="%s.jpg" % self.image.name.split('.')[0], content_type='image/jpeg', size=new_size, charset=None)
        else:
            print ('saving thubnail, no resize')
            output_thumb = BytesIO()
            thumb.save(output_thumb, format='JPEG', quality='keep')
            output_thumb.seek(0)
            new_size = len(output_thumb.getvalue())
            self.thumb = InMemoryUploadedFile(file=output_thumb, field_name='ImageField', name="%s.jpg" % self.image.name.split('.')[0], content_type='image/jpeg', size=new_size, charset=None)

    super(Photo, self).save(*args, **kwargs)

Большое спасибо заранее за объяснение.

...