I got a requirement to compress any uploaded images less than 500kb in file size, I have searched on google and all I can see is:
>>> foo = foo.resize((160,300),Image.ANTIALIAS)
>>> foo.save("path\\to\\save\\image_scaled.jpg",quality=95)
If I go with this approach I will have to check if the image is less than 500kb after compress, if not then go for lower quality and size.
Is there a better way to do it?
Those who know a bit of python can install python and use pip install pillow in command prompt(terminal for Linux users) to install pillow fork. Assemble all the files in a folder and keep the file Compress.py in the same folder. Run the python file with python.
To create your own compressed ZIP files, you must open the ZipFile object in write mode by passing 'w' as the second argument. When you pass a path to the write() method of a ZipFile object, Python will compress the file at that path and add it into the ZIP file.
To resize an image using PIL and maintain its aspect ratio with Python, we can open the image with Image. open . Then we calculate the new width and height to scale the image to according to the new width. And then we resize the image with the resize method and save the new image with the save method.
JPEG compression is not predictable beforehand. The method you described, compress & measure & try again, is the only way I know.
You can try compressing a number of typical images with different quality settings to get an idea of the optimum starting point, plus a way of guessing how changes to the setting will affect the size. That will get you to zero in on the optimum size without too many iterations.
You can also pass a file-like object to the save
function that doesn't bother to write to disk, just counts the bytes. Once you've determined the best settings then you can save it again to an actual file.
Edit: Here's an implementation of a suitable byte counting file object. Just check size
after the save.
class file_counter(object):
def __init__(self):
self.position = self.size = 0
def seek(self, offset, whence=0):
if whence == 1:
offset += self.position
elif whence == 2:
offset += self.size
self.position = min(offset, self.size)
def tell(self):
return self.position
def write(self, string):
self.position += len(string)
self.size = max(self.size, self.position)
Edit 2: Here's a binary search using the above to get the optimal quality
in the smallest number of attempts.
def smaller_than(im, size, guess=70, subsampling=1, low=1, high=100):
while low < high:
counter = file_counter()
im.save(counter, format='JPEG', subsampling=subsampling, quality=guess)
if counter.size < size:
low = guess
else:
high = guess - 1
guess = (low + high + 1) // 2
return low
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With