How to reduce a jpeg size to a ‘desired size’?

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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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:

<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e6cb9491cb94cbcb94cbcba6">[email protected]</a>   1 mark  staff     96835 11 Sep 18:21 result.jpg

If I change the target size to 50,000 bytes, I get:

<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ba97c8cd97c89797c89797fa">[email protected]</a>   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.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x