0

at my models.py i got a class named Post with and ImageField called postcover. I want to save every image in PNG format which is working fine so far but i have no idea how i could keep the actual image aspectio ratio after processing the image because currently i staticaly convert it into 4:3 format ratio while saveing it as 500 by 375 pixels.

def save(self, *args, **kwargs):
        super(Post, self).save(*args, **kwargs)
        if self.postcover:
            if os.path.exists(self.postcover.path):
                imageTemproary = Image.open(self.postcover)
                outputIoStream = BytesIO()
                imageTemproaryResized = imageTemproary.resize((500, 375))
                imageTemproaryResized.save(outputIoStream, format='PNG')
                outputIoStream.seek(0)
                self.postcover = InMemoryUploadedFile(outputIoStream, 'ImageField',
                                                  "%s.png" % self.postcover.name.split('.')[0], 'image/png',
                                                  sys.getsizeof(outputIoStream), None)
        super(Post, self).save(*args, **kwargs)

is there any way how i could set a max width and height while i keep the format?

UPDATE:

if i try it like this (see post below):

def save(self, *args, **kwargs):
    super(Post, self).save(*args, **kwargs)
    if self.postcover:
        if os.path.exists(self.postcover.path):
            imageTemproary = Image.open(self.postcover)
            outputIoStream = BytesIO()
            baseheight = 500
            hpercent = (baseheight / float(self.postcover.size[1]))
            wsize = int((float(self.postcover.size[0]) * float(hpercent)))
            imageTemproaryResized = imageTemproary.resize((wsize, baseheight))
            imageTemproaryResized.save(outputIoStream, format='PNG')
            outputIoStream.seek(0)
            self.postcover = InMemoryUploadedFile(outputIoStream, 'ImageField',
                                              "%s.png" % self.postcover.name.split('.')[0], 'image/png',
                                              sys.getsizeof(outputIoStream), None)
    super(Post, self).save(*args, **kwargs)

i just get the error:

'int' object is not subscriptable

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • I think it might be what you are looking for: https://stackoverflow.com/questions/273946/how-do-i-resize-an-image-using-pil-and-maintain-its-aspect-ratio – andreihondrari Apr 02 '19 at 10:13

2 Answers2

0

Maybe you can try like this:

image = Image.open(self.postcover)
baseheight = 500
hpercent = (baseheight / float(image.size[1]))
wsize = int((float(image.size[0]) * float(hpercent)))
imageTemproaryResized = image.resize((wsize, baseheight))

For more reference, please check this post: https://ruddra.com/posts/play-with-pillow/#resize-image

ruddra
  • 50,746
  • 7
  • 78
  • 101
  • Hey, thx for you help, i tried your solution but i get "'int' object is not subscriptable" can you please quickly check. Thank you –  Apr 02 '19 at 21:07
  • @Venom can you please add the full stacktrace? – ruddra Apr 03 '19 at 08:27
0

For a better understanding, i already was on discussion about this issue on another post here on stackoverflow, with this solution it's also possible to set a fixed baseheight for your image, this is especially usefull if you are using PNG format due to it's size. If your are using e.g. jpg format with this methode you will run into problems while processing colors or a transparent background with uploaded png files, so make sure you have propper field validator like this one, that just allows jpeg to be uploaded or simply just use png... :

validators.py

def image_file_extension(value):
    ext = os.path.splitext(value.name)[1]  # [0] returns path+filename
    valid_extensions = ['.jpg']
    if not ext.lower() in valid_extensions:
        raise ValidationError(u'Unsupported file extension, allowed is: jpg')

models.py

   def save(self, *args, **kwargs):
        super(Post, self).save(*args, **kwargs)
        if self.postcover:
            if os.path.exists(self.postcover.path):
                image = Image.open(self.postcover)
                outputIoStream = BytesIO()
                baseheight = 500
                hpercent = baseheight / image.size[1]
                wsize = int(image.size[0] * hpercent)
                imageTemproaryResized = image.resize((wsize, baseheight))
                imageTemproaryResized.save(outputIoStream, format='PNG')
                outputIoStream.seek(0)
                self.postcover = InMemoryUploadedFile(outputIoStream, 'ImageField',
                                                      "%s.png" % self.postcover.name.split('.')[0], 'image/png',
                                                      sys.getsizeof(outputIoStream), None)
        super(Post, self).save(*args, **kwargs)

please keep in mind that you need two super statements otherwise this type of flow wont work correctly at all.