Reputation: 11
I want to resize an image using resize()
method from PIL
based on a desired file size.
For example I have an image with file size of 14.1 MB, width x height of 3456 x 5184
. What will be its resolution if the desired file size is 2 MB ?
Tried some calculation my self like using this formula image_size = (width * height * bit_depth + headers) / 8
plus the aspect ration from the current status of the image, but It does not work as I expected.
Goal:
Finding desired height or width
known:
Upvotes: 0
Views: 665
Reputation: 3023
copying from here How to reduce a jpeg size to a 'desired size'? and here Python PIL: Find the size of image without writing it as a file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 27 18:26:54 2021
@author: Pietro
"""
import io
from PIL import Image
def SaveWithTargetFileSize(im, filename, target):
x, y =im.size
buffer = io.BytesIO()
im.save(buffer, format=mod_img, quality=100)
im_size = buffer.getbuffer().nbytes
if im_size <= target:
print('invalid target value ')
return
while im_size > target :
buffer = io.BytesIO()
im.save(buffer, format=mod_img, quality=100)
im_size = buffer.getbuffer().nbytes
im = im.resize((x,y))
# print(x,y ,' ', im_size)
x -= 1
y -= 1
print('image_size for target file_size :', im.size[0],' X ', im.size[1] ,' image_file_size :', im_size)
im.save(filename+'.'+mod_img.lower(), format=mod_img, quality=100)
im = Image.open('Immagine_6.tif')
x, y =im.size
typ_img = im.mode
mod_img = im.format
print('image size : ',x,' X ',y,' ',' image_type :', typ_img,' image_format :', mod_img)
SaveWithTargetFileSize(im, "result_2", 400000) # here the target values in bytes
you need to figure out file size target in bytes (or add a converter inside the code)
it is slow because resize each time by just 1 pixel from initial to target values
maybe somebody else will use a fastest approach.
as suggested by @thebjorn my attempt to bisection search
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 27 18:26:54 2021
@author: Pietro
"""
import io
from PIL import Image
from datetime import datetime
begin = datetime.now()
def SaveWithTargetFileSize(im, filename, target):
xmax, ymax = im.size
xmin = 0
ymin = 0
buffer = io.BytesIO()
im.save(buffer, format=mod_img, quality=100)
im_size = buffer.getbuffer().nbytes
im_size_original = im_size
if im_size <= target:
print('invalid target value ')
return
numGuesses = 0
while xmin < xmax and ymin < ymax:
x_x, y_y = (xmax - xmin)//2, (ymax - ymin)//2
im = im.resize((x_x, y_y))
buffer = io.BytesIO()
im.save(buffer, format=mod_img, quality=100)
im_size = buffer.getbuffer().nbytes
#print(im.size[0], im.size[1], ' ', im_size, ' guesses :',
# numGuesses, ' ', im_size, target, x_x, y_y, xmax, ymax, xmin, #ymin)
if im_size < target:
xmax += x_x
ymax += y_y
elif im_size > target:
xmax -= x_x
ymax -= y_y
if abs(im_size - target) < (target*1)//100:
if im_size > target:
approx = str(200-(im_size*100/target))
if im_size < target:
approx = str(im_size*100/target)
return print('\nbest approximation : ',approx+'%\n\n',im.size[0],' ', im.size[1], ' ', im_size,
' guesses : ', numGuesses,
' ', im_size,' ', target,' ', x_x,' ', y_y,' ', xmax,' ', ymax,' ', xmin,' ', ymin,' ', im_size_original,'\n\n',sep='')
print(im.size[0], im.size[1], ' ', im_size, ' guesses :', numGuesses,
' ', im_size, target, x_x, y_y, xmax, ymax, xmin, ymin, im_size_original,'\n\n')
numGuesses += 1
print('image_size for target file_size :',
im.size[0], ' X ', im.size[1], ' image_file_size :', im_size)
# im.save(filename+'.'+mod_img.lower(), format=mod_img, quality=100)
im = Image.open('Immagine_6.tif')
x, y = im.size
typ_img = im.mode
mod_img = im.format
print('image size : ', x, ' X ', y, ' ', ' image_type :',
typ_img, ' image_format :', mod_img)
SaveWithTargetFileSize(im, "result_5", 558999)
# SaveWithTargetFileSize(im, "result_5", 568000)
# SaveWithTargetFileSize(im, "result_4", 558999000)
print('\nTIME : ', datetime.now() - begin)
with this image setting image: image size : 520 X 409 image_type : RGBA image_format : TIFF it takes less than half the time of first keeping the print lines
Upvotes: 1