Batch Compress Images

Overview

This Python script gradually reduces the quality and colors of all .png's in the same directory until a target size is reached.

 1from PIL import Image, ImageEnhance
 2import os
 3 
 4# Define the target size in bytes
 5TARGET_SIZE = 1048576/3
 6 
 7def reduce_image_size(input_image_path, output_image_path):
 8    # Load the image
 9    image = Image.open(input_image_path)
10    
11    # Convert image to RGB if it's not (necessary for JPEG format)
12    if image.mode != 'RGB':
13        image = image.convert('RGB')
14 
15    # Start with full color depth
16    colors = 256
17 
18    # Initial quality
19    quality = 95
20 
21    # Initialize step counter
22    quality_steps = 0
23 
24    # Save image with decreasing quality and color depth until size is less than target size
25    while True:
26        # Use dithering when reducing color depth
27        if colors < 256:  # Apply dithering only when color depth is reduced
28            palette_image = image.quantize(colors=colors, method=Image.FASTOCTREE, dither=Image.FLOYDSTEINBERG)
29        else:
30            palette_image = image
31        
32        # Convert the palette image back to RGB for JPEG saving
33        rgb_image = palette_image.convert('RGB')
34 
35        # Save the image with the current quality and reduced color depth
36        rgb_image.save(output_image_path, format='JPEG', quality=quality, optimize=True, progressive=True)
37        
38        # Check the size of the saved image
39        size = os.path.getsize(output_image_path)
40 
41        print(f"Processing {input_image_path} -> Quality: {quality}, Colors: {colors}, Size: {size / 1024:.2f} KB")
42        
43        # If the image size is below the target size, break the loop
44        if size < TARGET_SIZE:
45            break
46        
47        # Reduce the quality two times before reducing color depth
48        if quality_steps < 2:
49            # Decrease the quality for the next iteration
50            quality -= 1
51            quality_steps += 1
52            # Ensure the quality does not go below 1
53            if quality < 1:
54                print("Quality is at minimum.")
55                break
56        else:
57            # Reset the quality step counter and reduce color depth
58            quality_steps = 0
59            # Reduce the number of colors
60            colors = max(16, colors - 1)  # Reduce colors by 1 each time, down to a minimum of 16 colors
61            # Ensure the color depth does not go below 16
62            if colors <= 16:
63                print("Color depth is at minimum.")
64                break
65 
66def optimize_directory_images(directory_path):
67    # List all files in the directory
68    for filename in os.listdir(directory_path):
69        # Process only PNG files
70        if filename.lower().endswith('.png'):
71            input_image_path = os.path.join(directory_path, filename)
72            output_image_path = os.path.join(directory_path, filename.replace('.png', '.jpg'))
73            
74            # Reduce image size and save as JPEG
75            reduce_image_size(input_image_path, output_image_path)
76 
77# Example usage
78directory_path = '.'  # Path to the directory containing PNG images (use '.' for the current directory)
79optimize_directory_images(directory_path)