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)
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) self.size = max(self.size, self.position) 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