A built-in parameter for saving JPEGs and PNGs is optimize.
from PIL import Image
foo = Image.open('path/to/image.jpg') # My image is a 200x374 jpeg that is 102kb large
foo.size # (200, 374)
# downsize the image with an ANTIALIAS filter (gives the highest quality)
foo = foo.resize((160,300),Image.ANTIALIAS)
foo.save('path/to/save/image_scaled.jpg', quality=95) # The saved downsized image size is 24.8kb
foo.save('path/to/save/image_scaled_opt.jpg', optimize=True, quality=95) # The saved downsized image size is 22.9kb
The optimize flag will do an extra pass on the image to find a way to reduce its size as much as possible. 1.9kb might not seem like much, but over hundreds/thousands of pictures, it can add up.
Now to try and get it down to 5kb to 10 kb, you can change the quality value in the save options. Using a quality of 85 instead of 95 in this case would yield: Unoptimized: 15.1kb Optimized : 14.3kb Using a quality of 75 (default if argument is left out) would yield: Unoptimized: 11.8kb Optimized : 11.2kb
I prefer quality 85 with optimize because the quality isn't affected much, and the file size is much smaller.
Answer from Ryan G on Stack Overflowpython - How to reduce the image file size using PIL - Stack Overflow
How to compress a picture less than a limit file size using python PIL library? - Stack Overflow
I had a genius moment this morning... use python to compress images to webp!
Trying to compress images with PIL but the file size isn't changing.
A built-in parameter for saving JPEGs and PNGs is optimize.
from PIL import Image
foo = Image.open('path/to/image.jpg') # My image is a 200x374 jpeg that is 102kb large
foo.size # (200, 374)
# downsize the image with an ANTIALIAS filter (gives the highest quality)
foo = foo.resize((160,300),Image.ANTIALIAS)
foo.save('path/to/save/image_scaled.jpg', quality=95) # The saved downsized image size is 24.8kb
foo.save('path/to/save/image_scaled_opt.jpg', optimize=True, quality=95) # The saved downsized image size is 22.9kb
The optimize flag will do an extra pass on the image to find a way to reduce its size as much as possible. 1.9kb might not seem like much, but over hundreds/thousands of pictures, it can add up.
Now to try and get it down to 5kb to 10 kb, you can change the quality value in the save options. Using a quality of 85 instead of 95 in this case would yield: Unoptimized: 15.1kb Optimized : 14.3kb Using a quality of 75 (default if argument is left out) would yield: Unoptimized: 11.8kb Optimized : 11.2kb
I prefer quality 85 with optimize because the quality isn't affected much, and the file size is much smaller.
lets say you have a model called Book and on it a field called 'cover_pic', in that case, you can do the following to compress the image:
from PIL import Image
b = Book.objects.get(title='Into the wild')
image = Image.open(b.cover_pic.path)
image.save(b.image.path,quality=20,optimize=True)
hope it helps to anyone stumbling upon it.
When you're changing the quality using PIL, the dimensions of the image does not change, it just changes the quality of the image using JPEG compression. By default the value is at 80, and thus changing the value to 75 will not reduce the size by much, you can change the value to about 60 without loosing a lot of picture quality. The value reduces logarithmically so if you want the exact math, you can read about JPEG compression. https://math.dartmouth.edu/archive/m56s14/public_html/proj/Marcus_proj.pdf
Unfortunately this is a property of JPEG compression and there is no strict inverse function (you can calculate it mathematically if you want large scale efficiency).
However, you can inefficiently brute force the calculation and get it close with the following. If you don't want the same size, just change the quality to a scaling factor and it should work similarly.
import os
from PIL import Image
def compress_under_size(size, file_path):
'''file_path is a string to the file to be custom compressed
and the size is the maximum size in bytes it can be which this
function searches until it achieves an approximate supremum'''
quality = 90 #not the best value as this usually increases size
current_size = os.stat(file_path).st_size
while current_size > size or quality == 0:
if quality == 0:
os.remove(file_path)
print("Error: File cannot be compressed below this size")
break
compress_pic(file_path, quality)
current_size = os.stat(file_path).st_size
quality -= 5
def compress_pic(file_path, qual):
'''File path is a string to the file to be compressed and
quality is the quality to be compressed down to'''
picture = Image.open(file_path)
dim = picture.size
picture.save(file_path,"JPEG", optimize=True, quality=qual)
processed_size = os.stat(file_path).st_size
return processed_size
for file in os.listdir("pics"):
try:
pic = f"./pics/{file}"
compress_under_size(10000,pic)
except Exception:
pass