In Python 3.x, I am using PIL to resize images, I know that we can reduce the height or width by subtraction or division by pixels. But, is it possible to resize an image to a desired size, say 200kb and remain its proportions? Assuming the image(s) is larger but the size is unknown.
Asked
Active
Viewed 3,711 times
6
-
1It would be difficult/impossible to predict without performing the encoding. If you're prepared to encode you could then do a binary search. – Peter Wood Sep 10 '18 at 14:04
-
You could bulk the file with garbage. – Peter Wood Sep 10 '18 at 14:18
-
http://freshmeat.sourceforge.net/projects/jpegfit – Peter Wood Sep 10 '18 at 14:18
-
https://www.perlmonks.org/?node_id=628683 – Peter Wood Sep 10 '18 at 14:19
-
@PeterWood, what do you mean by bulk the file with garbage? Thank you so much for your input. – moomoochen Sep 10 '18 at 14:26
-
**ImageMagick** provides exactly that capability. You could *"shell out"* with a subprocess and use the commandline tools as shown here https://stackoverflow.com/a/30194093/2836621 Or you could jpeg encode to a bytesio buffer in memory with varying quality using a binary search without writing to disk. – Mark Setchell Sep 10 '18 at 15:16
-
@MarkSetchell, I am so confused here.. so there is no way I can use PIL to achieve this? And I did go through your suggestion on ImageMagick, and I was completely lost. Am I be able to use Jupyter notebook to do this? – moomoochen Sep 11 '18 at 03:43
1 Answers
16
I am still learning Python, so there may be better ways, but here is a function that saves a PIL/Pillow image as a JPEG and allows you to specify a maximum size.
It uses a binary search to minimise the amount of work needed and it encodes into BytesIO
memory buffer to save writing images to disk. If anyone has any suggestions for improvements, please let me know!
#!/usr/local/bin/python3
import io
import math
import sys
import numpy as np
from PIL import Image
def JPEGSaveWithTargetSize(im, filename, target):
"""Save the image as JPEG with the given name at best quality that makes less than "target" bytes"""
# Min and Max quality
Qmin, Qmax = 25, 96
# Highest acceptable quality found
Qacc = -1
while Qmin <= Qmax:
m = math.floor((Qmin + Qmax) / 2)
# Encode into memory and get size
buffer = io.BytesIO()
im.save(buffer, format="JPEG", quality=m)
s = buffer.getbuffer().nbytes
if s <= target:
Qacc = m
Qmin = m + 1
elif s > target:
Qmax = m - 1
# Write to disk at the defined quality
if Qacc > -1:
im.save(filename, format="JPEG", quality=Qacc)
else:
print("ERROR: No acceptble quality factor found", file=sys.stderr)
################################################################################
# main
################################################################################
# Load sample image
im = Image.open('/Users/mark/sample/images/lena.png')
# Save at best quality under 100,000 bytes
JPEGSaveWithTargetSize(im, "result.jpg", 100000)
If I run that as is, with target size of 100,000 bytes, I get:
-rw-r--r--@ 1 mark staff 96835 11 Sep 18:21 result.jpg
If I change the target size to 50,000 bytes, I get:
-rw-r--r--@ 1 mark staff 49532 11 Sep 18:26 result.jpg
Keywords: Python, PIL, Pillow, JPEG, quality, quality setting, max size, maximum size, image, image processing, binary search.

Mark Setchell
- 191,897
- 31
- 273
- 432
-
I got an error from your else statement, "ERROR: No acceptble quality factor found" What did I do wrong? – moomoochen Sep 12 '18 at 03:21
-
1I can't tell for sure without seeing your image and the target size you specified. If you tried to reduce, say, an 8,000x6,000 pixel image to 5,000 bytes it will have had difficulties. Please share your image and target size, or try increasing the target size to give it a better chance of success. – Mark Setchell Sep 12 '18 at 06:40
-
1Can you clarify what size (in pixels) of image you tried to compress with this please and what target size you specified - because I have tried it successfully on many files. – Mark Setchell Sep 20 '18 at 15:54
-
sorry for my late response, may I know what IDE you're using? and what OS you're using? Thank you so much :) – moomoochen Sep 25 '18 at 01:39
-
1I don't use an IDE, I just type the code into an editor (`vi`, not that it makes any difference) and save it and run it. I tested the code on a Mac and under debian. You know the formatting (indentation) is critical, don't you? – Mark Setchell Sep 25 '18 at 06:20