Reputation: 445
I'm trying to compress a jpg file using PIL (to be more specific, Pillow)
I know images can be compressed by doing this:
from PIL import Image
im = Image.open(img_path)
im = im.resize(new_size, Image.ANTIALIAS)
im.save(output_path, optimize=True, quality=50)
But I want to go further by tweaking more params, like this:
im.save(output_path, optimize=True, quality=50, jfif_unit=1, dpi=(72,72), jfif_density=(72,72))
Unfortunately, it does not change dpi or density at all. How am I suppose to achieve that?
Upvotes: 15
Views: 34329
Reputation: 353
With a little help from some articles here and there I came up with the below:
def set_image_dpi_resize(image):
"""
Rescaling image to 300dpi while resizing
:param image: An image
:return: A rescaled image
"""
length_x, width_y = image.size
factor = min(1, float(1024.0 / length_x))
size = int(factor * length_x), int(factor * width_y)
image_resize = image.resize(size, Image.ANTIALIAS)
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='1.png')
temp_filename = temp_file.name
image_resize.save(temp_filename, dpi=(300, 300))
return temp_filename
The above changes the dpi (to 300) and resizes the image. It saves all the results to a temporary image.
Though you may not want to change the size sometimes but only the dpi, therefore you can use the below:
def set_image_dpi(image):
"""
Rescaling image to 300dpi without resizing
:param image: An image
:return: A rescaled image
"""
image_resize = image
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
temp_filename = temp_file.name
image_resize.save(temp_filename, dpi=(300, 300))
return temp_filename
For all the above you will need two imports:
from PIL import Image
import tempfile
I understand that if you run a code to check many images in batch (e.g. I am looping through thousands of photos, doing this operation for each one of them) you do not want your App Data temp folder to be full with temps. Therefore I also have a delete close method (to close the file) and a delete method (to delete it from my temp). Please note that you cannot delete it without closing it:
def close_image(image):
"""
Closes opened image
:param image: An image
:return: None
"""
image.close()
def removing_file(path):
"""
Removing file by path
:param path: The path of a file
:return: None
"""
# Try/except library import
try:
import os # Miscellaneous OS library
except ImportError as ImportException:
raise ImportError("Cannot import needed libraries. Please contact administrator and give the code FN0001")
os.remove(path)
Hope it helps.
Upvotes: 18