2016-08-29 20 views
3

djangoアプリケーションでアップロードする前に画像ファイルを圧縮しようとしています。Django、StringIO、またはBytesIOで画像を読み取るのにどちらを使う必要がありますか?

私は素敵なコードスニペットのサイトが見つかりました:https://djangosnippets.org/snippets/10460/

をしかし、それはpython3では動作しません。問題は約strまたはbyteと思います。

誰かがStringIOの代わりにBytesIOを使用することをお勧めします。

私はこのように自分のコードを編集します。

from django.db import models 
from django.core.urlresolvers import reverse 
from django.utils import timezone 
from django.utils.text import slugify 
from django.core.files.uploadedfile import InMemoryUploadedFile 

from PIL import Image as Img 
from io import StringIO, BytesIO 

def upload_location(instance, file_name): 
    return "{}/{}/{}/{}".format(
     "album", 
     instance.day, 
     instance.week, 
     file_name 
    ) 


class Album(models.Model): 

    DAYS = (
     ('Sun', '일요일'), 
     ('Mon', '월요일'), 
    ) 
    name = models.CharField(max_length=50) 
    description = models.CharField(max_length=100, blank=True) 
    image = models.ImageField(upload_to=upload_location) 
    day = models.CharField(max_length=3, choices=DAYS) 
    week = models.IntegerField() 
    slug = models.SlugField(unique=True, allow_unicode=True) 
    date = models.DateField() 

    created_at = models.DateTimeField(auto_now_add=True) 
    updated_at = models.DateTimeField(auto_now=True) 

    class Meta: 
     ordering = ['day', 'week'] 

    def __str__(self): 
     return "{} - {}주차".format(self.get_day_display(), self.week) 

    def get_absolute_url(self): 
     return reverse(
      "album:album_detail", 
      kwargs={ 
       "slug": self.slug 
      } 
     ) 

    def save(self, *args, **kwargs): 
     if not self.id: 
      self.slug = self.slug + "주차" 

     if self.image: 
      img = Img.open(BytesIO(self.image.read())) 
      if img.mode != 'RGB': 
       img = img.convert('RGB') 
      img.thumbnail((self.image.width/1.5,self.image.height/1.5), Img.ANTIALIAS) 
      output = BytesIO() 
      img.save(output, format='JPEG', quality=70) 
      output.seek(0) 
      self.image= InMemoryUploadedFile(
       output,'ImageField', 
       "%s.jpg" %self.image.name.split('.')[0], 
       'image/jpeg', 
       output.len, None 
      ) 
     super().save(*args, **kwargs) 

しかし、それはエラーが発生します。'_io.BytesIO' object has no attribute 'len' - 私のコードで>output.lenは、エラーが発生します。

私は、StringIOの代わりにBytesIOを使用するのが正しいことを疑うようになります。

また、私のコードを編集する方法も必要です。ありがとう。

+0

あなたは([それはバッファ 最初だ取得]で 'BytesIO'オブジェクトのデータの長さを得ることができますhttps://docs.python.org/3/library/io.html#io.BytesIO.getbuffer )。次に 'len(buffer)'で長さを取得できます。また、バッファー 'view'を' buf.release() 'で解放して、' BytesIO'オブジェクトをクローズする必要があります( 何らかの理由でやっていないようです)。 – Sevanteri

+0

バッファのサイズだけではなく、BytesIOオブジェクト全体のサイズが必要になるかもしれません。あなたは['sys.getsizeof'](http://stackoverflow.com/questions/26827055/python-how-to-get-iobytes-allocated-memory-length)でそれを得ることができます。 – Sevanteri

+0

コードを修正するにはどうすればよいですか? – user3595632

答えて

2

withステートメントを使用するようにコードを変更したので、ファイルを自分で閉じる必要はありません。

def save(self, *args, **kwargs): 
    if not self.id: 
     self.slug = self.slug + "주차" 

    if self.image: 
     with Img.open(BytesIO(self.image.read())) as img: 
      if img.mode != 'RGB': 
       img = img.convert('RGB') 

      img.thumbnail((self.image.width/1.5,self.image.height/1.5), Img.ANTIALIAS) 
      with BytesIO() as output: 
       img.save(output, format='JPEG', quality=70) 
       output.seek(0) 
       self.image = InMemoryUploadedFile(
        output,'ImageField', 
        "%s.jpg" %self.image.name.split('.')[0], 
        'image/jpeg', 
        output.getbuffer().nbytes, None 
       ) 

    super().save(*args, **kwargs) 
関連する問題