Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which one I have to use to read image in Django, StringIO or BytesIO?

I'm trying to compress the image file before uploading in my django application.

I found nice code snippet site : https://djangosnippets.org/snippets/10460/

but It doesn't work in python3. I think the problem is about str or byte.

Someone advise to use BytesIO instead of StringIO.

So, I edit my code like this.

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)

But it occurs an error : '_io.BytesIO' object has no attribute 'len' --> output.len in my code occurs an error.

I start to doubt that It is right way to use BytesIO instead of StringIO.

And need some helps how to edit my code, too. Thanks.

like image 410
user3595632 Avatar asked Oct 19 '22 02:10

user3595632


1 Answers

I modified the code to use the with statement so there is no need to close the files yourself.

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)
like image 65
Sevanteri Avatar answered Oct 21 '22 06:10

Sevanteri