Automated Batch Image Compression with Python
Published: July 30, 2024 | Last Modified: June 18, 2025
Tags: python image-processing optimization pil pillow batch-processing
Categories: Python Image Processing
This Python script gradually reduces the quality and colors of all .png’s in the same directory until a target size is reached.
from PIL import Image, ImageEnhance
import os
# Define the target size in bytes
TARGET_SIZE = 1048576/3
def reduce_image_size(input_image_path, output_image_path):
# Load the image
image = Image.open(input_image_path)
# Convert image to RGB if it's not (necessary for JPEG format)
if image.mode != 'RGB':
image = image.convert('RGB')
# Start with full color depth
colors = 256
# Initial quality
quality = 95
# Initialize step counter
quality_steps = 0
# Save image with decreasing quality and color depth until size is less than target size
while True:
# Use dithering when reducing color depth
if colors < 256: # Apply dithering only when color depth is reduced
palette_image = image.quantize(colors=colors, method=Image.FASTOCTREE, dither=Image.FLOYDSTEINBERG)
else:
palette_image = image
# Convert the palette image back to RGB for JPEG saving
rgb_image = palette_image.convert('RGB')
# Save the image with the current quality and reduced color depth
rgb_image.save(output_image_path, format='JPEG', quality=quality, optimize=True, progressive=True)
# Check the size of the saved image
size = os.path.getsize(output_image_path)
print(f"Processing {input_image_path} -> Quality: {quality}, Colors: {colors}, Size: {size / 1024:.2f} KB")
# If the image size is below the target size, break the loop
if size < TARGET_SIZE:
break
# Reduce the quality two times before reducing color depth
if quality_steps < 2:
# Decrease the quality for the next iteration
quality -= 1
quality_steps += 1
# Ensure the quality does not go below 1
if quality < 1:
print("Quality is at minimum.")
break
else:
# Reset the quality step counter and reduce color depth
quality_steps = 0
# Reduce the number of colors
colors = max(16, colors - 1) # Reduce colors by 1 each time, down to a minimum of 16 colors
# Ensure the color depth does not go below 16
if colors <= 16:
print("Color depth is at minimum.")
break
def optimize_directory_images(directory_path):
# List all files in the directory
for filename in os.listdir(directory_path):
# Process only PNG files
if filename.lower().endswith('.png'):
input_image_path = os.path.join(directory_path, filename)
output_image_path = os.path.join(directory_path, filename.replace('.png', '.jpg'))
# Reduce image size and save as JPEG
reduce_image_size(input_image_path, output_image_path)
# Example usage
directory_path = '.' # Path to the directory containing PNG images (use '.' for the current directory)
optimize_directory_images(directory_path)