JustToThePoint English Website Version
JustToThePoint en español
JustToThePoint in Thai

Python Bulk Image Optimize

There are no problems we cannot solve together, and very few that we can solve by ourselves, Lyndon B. Johnson.

Learn everything you can, anytime you can, from anyone you can – there will always come a time when you will be grateful you did, Sarah Caldwell.

If the only tool you have is a hammer, you tend to see every problem as a nail, Abraham Maslow.

The aim is to provide a simple script to resize and compress all your images recursively at once, that is, bulk resize and compress images with Python and Pillow.

image info

"""
File: compressImage.py
Author: Máximo Núñez Alarcón
Description: It aims to automate the process of resizing and compressing images in a directory and provides logging to track the changes.
Usage: python compressImage.py (it needs to activate the environment)
"""

import os # Interact with the operating system.
from PIL import Image # PIL allows opening, manipulating, and saving many different image file formats.
import shutil # Functions to operate on files and directories
from util import check_all_files, printUrl, append_to_file, cleanLog

def compress_image(image_path, max_size_mb=2, max_height=1700):
    """
    Compresses an image to reduce its file size while maintaining aspect ratio.

    Args:
        image_path (str): The path to the image file.
        max_size_mb (float, optional): The maximum allowed size in megabytes (defaults is 2 mb).
        max_height (int, optional): The maximum height of the image in pixels (defaults to 1700).

    Returns:
        None

    """
    
    # If the image is corrupted or the path does not exist, then remove it and/or return
    try:
        with Image.open(image_path) as img:
            pass
    except FileNotFoundError:
        print(f"File '{image_path}' does not exist.")
        append_to_file(f"File '{image_path}' does not exist.")
        return 
    except Exception as e:
        os.remove(image_path)
        print(f"An error occurred while processing '{image_path}': {e}")
        append_to_file(f"An error occurred while processing '{image_path}': {e}")
        return

    # Open the image
    with Image.open(image_path) as img:
        # os.path.getsize(image_path) Get the image size in bytes.
        img_size_mb = os.path.getsize(image_path) / (1024 * 1024)  # Convert bytes to megabytes
        
        # Check if the image size is already within the limit
        if img_size_mb <= max_size_mb:
            # Return if image is already within the size limit
            return
        
        # Get the original width and height in pixels of the image
        width, height = img.size
        
        # Calculate the new width and height while maintaining aspect ratio
        if height > max_height:
            # height --> new_height
            # width --> new_width
            new_height = max_height
            new_width = int((width / height) * max_height)
        else:
            new_width = width
            new_height = height
        
        # Resize the image. The method size() required: size in pixels, as a 2-tuple: (width, height),
        # resample, an optional resampling filter. PIL.Image.LANCZOS is a high-quality downsampling filter.
        # It resize the image. It doesn't modify the original. 
        img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
        
        # Save the resized image under the given filename with reduced quality
        img.save(image_path, quality=80)
        
        # Get the new size of the compressed image
        new_size_mb = os.path.getsize(image_path) / (1024 * 1024)
        append_to_file(f"Image {image_path} compressed to {new_size_mb:.2f} MB with dimensions {new_width}x{new_height} pixels.")

 
def apply_func_image_files(path, func):
    """
    Recursively list and apply "func" to all image files in a directory and its subdirectories.
    
    Args:
    - path (str): The path to the directory to search.
    - func (function): The function to apply to each image file found.
    """
    # Iterate over all files and directories in the given path. 
    # os.walk() generate the file names in a directory tree by traversing recursively the tree. 
    # For each directory in the tree rooted at directory top (including top itself), it yields a 3-tuple (dirpath, dirnames, filenames).
    for root, dirs, files in os.walk(path, topdown=True):
        for file in files:
            # Check if the file is an image based on its extension
            if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):
                # Get the full path of the image file
                image_path = os.path.join(root, file)
                # Call the provided function with the image path
                func(image_path)

def get_directory_size(directory):
    # Get the size of the directory in bytes

    size_in_bytes = shutil.disk_usage(directory).used

    # Convert the size from bytes to megabytes
    size_in_mb = size_in_bytes / (1024 * 1024)  

    # Return the size in megabytes
    return size_in_mb

def my_main():
    cleanLog()
    directory_path = "/your/path"  # From this directory, the script will recursively work.
    size_in_mb = get_directory_size(directory_path) # Track the size of your directory before and after the script
    append_to_file("-------------------BEGIN--------------------------------------")
    # The f before the string indicates that it is a formatted string literal, 
    # and {} are placeholders for variables to be inserted into the string.
    append_to_file(f"Total size of {directory_path}: {size_in_mb:.2f} MB")
    apply_func_image_files(directory_path, compress_image)
    size_in_mb = get_directory_size(directory_path)
    append_to_file(f"Total size of {directory_path}: {size_in_mb:.2f} MB")
    append_to_file("-------------------END--------------------------------------")

if __name__ == "__main__":
    my_main()
Bitcoin donation

JustToThePoint Copyright © 2011 - 2024 Anawim. ALL RIGHTS RESERVED. Bilingual e-books, articles, and videos to help your child and your entire family succeed, develop a healthy lifestyle, and have a lot of fun. Social Issues, Join us.

This website uses cookies to improve your navigation experience.
By continuing, you are consenting to our use of cookies, in accordance with our Cookies Policy and Website Terms and Conditions of use.