Tl;DR: Is it possible to manipulate size of image in KB to the desired size?
There are 4 ways to get an image size as answered by Mark in my another question and I'm wondering if there's any relation of ANY of the size to the number of pixels?
(7460,24300,1),(2549,6075,2),(1303,2700,3),(808,1518,4), (552,972,5)
These are the (os_stat_size, numpy_array_size, image_factor)
image_factor == factor by which the image has been resized
As you can see the resizing factor is not proportional to the size in KB.
Code given below is working perfectly for resizing. I am experimenting on manipulating image size in KBs instead of pixels. I did an experiment to reduce the overall image size by 50%. The idea is that given any depth, it should be constant and the pixels should correspond to the image size in linear fashion (thinking metadata remains constant)
I did the experiment and did not get results with jpeg
. So I thought there might be some problem with the extension as I found this second answer saying :
Jpeg files don't have bit depth in the same manner as GIF or PNG files. The transform used to create the Jpeg data renders a continuous colour spectrum on decompression.
So I tried the same experiment with the PNG
and it was same. Below are my experiments with both the versions with commented out exchange between jpeg
and png
Helper code and imports: Working fine
from PIL import Image
import numpy as np
import requests
from io import BytesIO
from os import stat
import os
import sys
def resize(image:Image, current_size:tuple, new_width_height:float)->Image:
'''
Resize and return Given Image
args:
image: Image object
current_size: Image size as (width, height)
new_width_height = Reshaped image's width and height. If integer is given, it'll keep the aspect ratio as it is by shrinking the Bigger dimension (width or height) to the max of new_width_height and then shring the smaller dimension accordingly
'''
fixed_size = True if isinstance(new_width_height, int) else False
w, h = current_size
if fixed_size:
if h > w:
fixed_height = new_width_height
height_percent = (fixed_height / float(h))
width_size = int((float(w) * float(height_percent)))
image = image.resize((width_size, fixed_height), Image.Resampling.LANCZOS) # # Try Image.NEAREST
else:
fixed_width = new_width_height
width_percent = (fixed_width / float(w))
height_size = int((float(h) * float(width_percent)))
image = image.resize((fixed_width, height_size), Image.Resampling.LANCZOS)
else:
w, h = int(new_width_height[0]), int(new_width_height[1])
image = image.resize((w,h), Image.Resampling.LANCZOS)
return image
Experiment:
- Actual image stats:
url = "https://wallpaperaccess.com/full/508751.jpg"
buffer = BytesIO(requests.get(url).content)
size_buffer = buffer.getbuffer().nbytes//1024
image = Image.open(buffer)
size_uncompressed = len(image.tobytes()) // 1024
# image.save('./wallpaper.jpeg', format = 'jpeg', quality = 'keep', subsampling = False)
# size_os = os.stat('./wallpaper.jpeg').st_size // 1024
image.save('./wallpaper.PNG', format = 'PNG', quality = 'keep', subsampling = False)
size_os = os.stat('./wallpaper.PNG').st_size // 1024
numpy_size = sys.getsizeof(np.array(image)) // 1024 # same as len(image.tobytes())
print(image.size, image.format, image.mode, str(size_buffer)+' KB (buffer.getbuffer().nbytes//1024)', str(size_os)+' KB (os.stat().st_size // 1024)', str(size_uncompressed)+' KB (len(image.tobytes()) // 1024)', str(numpy_size)+' KB (sys.getsizeof(np.array(image)) // 1024)')
- Resized image stats:
image = resize(image, image.size, max(image.size)//2)
# image.format = "JPEG" # as it'll throw error when using quality='keep' with jpeg
image.format = "PNG"
size_uncompressed = len(image.tobytes()) // 1024
buffer = BytesIO()
# image.save(buffer, format="JPEG", format = 'jpeg', quality = 'keep', subsampling = False)
image.save(buffer, format="PNG")
size_buffer = buffer.getbuffer().nbytes//1024
# image.save('./resized_wallpaper.jpeg', format = 'jpeg', quality = 'keep', subsampling = False)
# size_os = os.stat('./resized_wallpaper.jpeg').st_size // 1024
image.save('./resized_wallpaper.PNG', format = 'PNG')
size_os = os.stat('./resized_wallpaper.PNG').st_size // 1024
numpy_size = sys.getsizeof(np.array(image)) // 1024
print(image.size, image.format, image.mode, str(size_buffer)+' KB (buffer.getbuffer().nbytes//1024)', str(size_os)+' KB (os.stat().st_size // 1024)', str(size_uncompressed)+' KB (len(image.tobytes()) // 1024)',str(numpy_size)+' KB (sys.getsizeof(np.array(image)) // 1024)')
None of them are actually linear. Is it normal or I'm doing something wrong?