0

I'm using django-resized to reduce sizes of images when they are uploaded to AWS S3.

The resizing works fine when the image is wider than its height. However, when image height is bigger than its width then the output image is rotated by 90 degrees and its width is bigger than its height.

models.py

from django_resized import ResizedImageField

class Catch(models.Model):
    fish_type = models.CharField("Fish Type", max_length=50, choices=fish_choices, default="Carp")
    catch_id = models.AutoField(primary_key=True)
    weight = models.DecimalField("Weight", max_digits=5, decimal_places=2)
    length = models.DecimalField("Length", max_digits=5, decimal_places=2, blank=True, null=True)
    datetime = models.DateTimeField("Catch Time", auto_now=False, auto_now_add=False)
    image = ResizedImageField(size=[1080, 1350], quality=95, null=True, blank=True, default="default_img.png", upload_to="catch_images/")
    fisherman = models.ForeignKey(Fisherman, on_delete=models.CASCADE)
    trip = models.ForeignKey(Trips, on_delete=models.CASCADE)
    hookbait_name = models.CharField('Csali megnevezése', max_length=120, blank=True, null=True)
    hookbait = models.ForeignKey(HookBait, on_delete=models.SET_NULL, blank=True, null=True)

settings.py

DJANGORESIZED_DEFAULT_KEEP_META = True
DJANGORESIZED_DEFAULT_FORCE_FORMAT = 'JPEG'
DJANGORESIZED_DEFAULT_FORMAT_EXTENSIONS = {'JPEG': ".jpg"}
DJANGORESIZED_DEFAULT_NORMALIZE_ROTATION = True

I only want to reduce sizes of images while they're preserving the aspect ratio.

Thanks in advance for any help.

EDIT!

I managed to solve the problem on my own. I used pillow to resize images but I also had to rotate them based on the orientation tag.

The rigth code is here:

models.py

from PIL import Image, ExifTags
from io import BytesIO
from django.core.files import File

class Catch(models.Model):
    fish_type = models.CharField("Fish Type", max_length=50, choices=fish_choices, default="Carp")
    catch_id = models.AutoField(primary_key=True)
    weight = models.DecimalField("Weight", max_digits=5, decimal_places=2)
    length = models.DecimalField("Length", max_digits=5, decimal_places=2, blank=True, null=True)
    datetime = models.DateTimeField("Catch Time", auto_now=False, auto_now_add=False)
    image = models.ImageField(null=True, blank=True, default="default_img.png", upload_to="catch_images/")
    fisherman = models.ForeignKey(Fisherman, on_delete=models.CASCADE)
    trip = models.ForeignKey(Trips, on_delete=models.CASCADE)
    hookbait_name = models.CharField('Csali megnevezése', max_length=120, blank=True, null=True)
    hookbait = models.ForeignKey(HookBait, on_delete=models.SET_NULL, blank=True, null=True)

    class Meta:
        verbose_name = "Catch"
        verbose_name_plural = "Catches"
    
    def save(self, *args, **kwargs):
        if self.image:
            img = Image.open(BytesIO(self.image.read()))
            
            if hasattr(img, '_getexif'):
                exif = img._getexif()
                if exif:
                    for tag, label in ExifTags.TAGS.items():
                        if label == 'Orientation':
                            orientation = tag
                            break
                    if orientation in exif:
                        if exif[orientation] == 3:
                            img = img.rotate(180, expand=True)
                        elif exif[orientation] == 6:
                            img = img.rotate(270, expand=True)
                        elif exif[orientation] == 8:
                            img = img.rotate(90, expand=True)

            img.thumbnail((1080,1080), Image.ANTIALIAS)
            output = BytesIO()
            img.save(output, format='JPEG', quality=95)
            output.seek(0)
            self.image = File(output, self.image.name) 

        return super().save(*args, **kwargs)
Bence
  • 25
  • 6

2 Answers2

0

You should use PIL/pillow for this purpose. Edit your model(s) like this and all the images will be resized before saving to db.

You can do something like this:

from PIL import Image as Img
import io
from django.core.files.uploadhandler import InMemoryUploadedFile

class Catch(models.Model):
   #rest fields here
   image=models.ImageField(upload_to='Media/Users')

   def save(self):
      if self.image:
          img = Img.open(io.BytesIO(self.image.read()))
          if img.mode != 'RGB':
              img = img.convert('RGB')
          img.thumbnail((100,100), Img.ANTIALIAS)  #(width,height)
          output = io.BytesIO()
          img.save(output, format='JPEG')
          output.seek(0)
          self.image= InMemoryUploadedFile(output,'ImageField', "%s.jpg" 
                      %self.image.name.split('.')[0], 'image/jpeg',"Content- 
                      Type: charset=utf-8", None)
      super(Catch, self).save()

Note: The thumbnail function also reduce the size of the image. Here I have given width and height 100px for the output image. Just change the tuple values as per your requirement (width,height)

Also, you can use resize function instead of thumbnail if you only want to do image resizing.

itsmehemant7
  • 339
  • 1
  • 8
  • Thanks. There is something with AWS S3 because images are still rotated away, however the resizing works perfectly in development. Any idea? – Bence Jul 14 '21 at 08:17
  • I think using base64 could be a good alternative. Save your image in base64 string format on aws s3. When you fetch image, you can directly use base64 string in html image src attribute or can convert base64 string into image before serving. Here is a stackoverflow thread for using base64 https://stackoverflow.com/questions/8499633/how-to-display-base64-images-in-html – itsmehemant7 Jul 14 '21 at 12:45
0

There is a bug with browsers that when you take a photo with a mobile phone from the front and want to upload it to a form, for example for your profile, the image is flipped ( read docs)

If you are using the package django-resized, then you need to add False to DJANGORESIZED_DEFAULT_NORMALIZE_ROTATION in settings.py

DJANGORESIZED_DEFAULT_NORMALIZE_ROTATION = False
darl1ne
  • 334
  • 3
  • 11