Skip to content

Commit c2671e4

Browse files
committedJan 25, 2022
add compress images tutorial
1 parent 0d3e385 commit c2671e4

File tree

6 files changed

+94
-0
lines changed

6 files changed

+94
-0
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,6 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
186186
- [How to Extract Video Metadata in Python](https://www.thepythoncode.com/article/extract-media-metadata-in-python). ([code](python-for-multimedia/extract-video-metadata))
187187
- [How to Record a Specific Window in Python](https://www.thepythoncode.com/article/record-a-specific-window-in-python). ([code](python-for-multimedia/record-specific-window))
188188
- [How to Add Audio to Video in Python](https://www.thepythoncode.com/article/add-audio-to-video-in-python). ([code](python-for-multimedia/add-audio-to-video))
189+
- [How to Compress Images in Python](https://www.thepythoncode.com/article/compress-images-in-python). ([code](python-for-multimedia/compress-image))
189190

190191
For any feedback, please consider pulling requests.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# [How to Compress Images in Python](https://www.thepythoncode.com/article/compress-images-in-python)
2+
To run this:
3+
- `pip3 install -r requirements.txt`
4+
- `python compress_image.py --help`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import os
2+
from PIL import Image
3+
4+
5+
def get_size_format(b, factor=1024, suffix="B"):
6+
"""
7+
Scale bytes to its proper byte format
8+
e.g:
9+
1253656 => '1.20MB'
10+
1253656678 => '1.17GB'
11+
"""
12+
for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
13+
if b < factor:
14+
return f"{b:.2f}{unit}{suffix}"
15+
b /= factor
16+
return f"{b:.2f}Y{suffix}"
17+
18+
19+
20+
def compress_img(image_name, new_size_ratio=0.9, quality=90, width=None, height=None, to_jpg=True):
21+
# load the image to memory
22+
img = Image.open(image_name)
23+
# print the original image shape
24+
print("[*] Image shape:", img.size)
25+
# get the original image size in bytes
26+
image_size = os.path.getsize(image_name)
27+
# print the size before compression/resizing
28+
print("[*] Size before compression:", get_size_format(image_size))
29+
if new_size_ratio < 1.0:
30+
# if resizing ratio is below 1.0, then multiply width & height with this ratio to reduce image size
31+
img = img.resize((int(img.size[0] * new_size_ratio), int(img.size[1] * new_size_ratio)), Image.ANTIALIAS)
32+
# print new image shape
33+
print("[+] New Image shape:", img.size)
34+
elif width and height:
35+
# if width and height are set, resize with them instead
36+
img = img.resize((width, height), Image.ANTIALIAS)
37+
# print new image shape
38+
print("[+] New Image shape:", img.size)
39+
# split the filename and extension
40+
filename, ext = os.path.splitext(image_name)
41+
# make new filename appending _compressed to the original file name
42+
if to_jpg:
43+
# change the extension to JPEG
44+
new_filename = f"{filename}_compressed.jpg"
45+
else:
46+
# retain the same extension of the original image
47+
new_filename = f"{filename}_compressed{ext}"
48+
try:
49+
# save the image with the corresponding quality and optimize set to True
50+
img.save(new_filename, quality=quality, optimize=True)
51+
except OSError:
52+
# convert the image to RGB mode first
53+
img = img.convert("RGB")
54+
# save the image with the corresponding quality and optimize set to True
55+
img.save(new_filename, quality=quality, optimize=True)
56+
print("[+] New file saved:", new_filename)
57+
# get the new image size in bytes
58+
new_image_size = os.path.getsize(new_filename)
59+
# print the new size in a good format
60+
print("[+] Size after compression:", get_size_format(new_image_size))
61+
# calculate the saving bytes
62+
saving_diff = new_image_size - image_size
63+
# print the saving percentage
64+
print(f"[+] Image size change: {saving_diff/image_size*100:.2f}% of the original image size.")
65+
66+
67+
if __name__ == "__main__":
68+
import argparse
69+
parser = argparse.ArgumentParser(description="Simple Python script for compressing and resizing images")
70+
parser.add_argument("image", help="Target image to compress and/or resize")
71+
parser.add_argument("-j", "--to-jpg", action="store_true", help="Whether to convert the image to the JPEG format")
72+
parser.add_argument("-q", "--quality", type=int, help="Quality ranging from a minimum of 0 (worst) to a maximum of 95 (best). Default is 90", default=90)
73+
parser.add_argument("-r", "--resize-ratio", type=float, help="Resizing ratio from 0 to 1, setting to 0.5 will multiply width & height of the image by 0.5. Default is 1.0", default=1.0)
74+
parser.add_argument("-w", "--width", type=int, help="The new width image, make sure to set it with the `height` parameter")
75+
parser.add_argument("-hh", "--height", type=int, help="The new height for the image, make sure to set it with the `width` parameter")
76+
args = parser.parse_args()
77+
# print the passed arguments
78+
print("="*50)
79+
print("[*] Image:", args.image)
80+
print("[*] To JPEG:", args.to_jpg)
81+
print("[*] Quality:", args.quality)
82+
print("[*] Resizing ratio:", args.resize_ratio)
83+
if args.width and args.height:
84+
print("[*] Width:", args.width)
85+
print("[*] Height:", args.height)
86+
print("="*50)
87+
# compress the image
88+
compress_img(args.image, args.resize_ratio, args.quality, args.width, args.height, args.to_jpg)
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Pillow
Loading

0 commit comments

Comments
 (0)