DEV Community

Cover image for Image Processing Script: PNG Converter and Resizer
Muhammad Usman
Muhammad Usman

Posted on

Image Processing Script: PNG Converter and Resizer

Image Processing Script:

This Python script allows you to automatically process images by ensuring transparency, cropping unused spaces, resizing to fit a 2:1 canvas, and cleaning up the filenames. Here's what it does:

  • Transparency Handling: Ensures that images are in PNG format with transparency. If the image has a white background, it's replaced with transparency.

  • Space Removal: Removes spaces from image filenames and replaces them with underscores (_).

  • Filename Shortening: If a filename is too long, it truncates it to a maximum length (30 characters).

  • Cropping: The script crops any extra unused space around the image.

  • Resizing: Resizes the image to fit a 2:1 canvas (e.g., 400x200), ensuring the aspect ratio is preserved and the image is centered on the canvas.

  • Logs Skipped Images: If any image is skipped due to being unsupported, empty, or fully transparent, it logs the skipped filenames.

Dependencies:

Pillow (Python Imaging Library fork)
You can install it with:
pip install Pillow

How to Use:

Place your images in a folder (e.g., images).
Run the script, and it will automatically process and save the images in a folder (e.g., edited_images).
The processed images will be resized, centered, and saved in PNG format.
Note:
The script ensures that only valid images are processed and any issues with unsupported formats or transparency are logged in the console.

Here the script started:

from PIL import Image
import os

def ensure_transparency(image):
    # Convert the image to RGBA (if it's not already in that mode)
    if image.mode != 'RGBA':
        image = image.convert('RGBA')

    # If the image doesn't have a transparent background, add one
    if image.getchannel('A').getextrema()[0] != 0:
        # Replace the white or non-transparent background with transparency
        image = image.convert('RGBA')
        image_data = image.getdata()
        new_data = []
        for item in image_data:
            # Change all white (also shades of whites) pixels to transparent
            if item[0] in range(240, 256) and item[1] in range(240, 256) and item[2] in range(240, 256):
                new_data.append((255, 255, 255, 0))  # Replace white with transparency
            else:
                new_data.append(item)
        image.putdata(new_data)
    return image

def process_image(input_path, output_path, target_width, target_height):
    # Open the image
    try:
        image = Image.open(input_path)
    except IOError:
        print(f"Error opening {input_path}, skipping...")
        return None

    # Ensure the image is PNG and has transparency
    image = ensure_transparency(image)

    # Get the bounding box of the non-empty region (crops the unused space)
    bbox = image.getbbox()

    if bbox is None:
        print(f"Image {input_path} has no content or is fully transparent, skipping...")
        return None

    # Crop the image using the bounding box
    cropped_image = image.crop(bbox)

    # Get the dimensions of the cropped image
    img_width, img_height = cropped_image.size
    aspect_ratio = target_width / target_height

    # Calculate new dimensions to fit the image within the 2:1 aspect ratio
    if img_width / img_height > aspect_ratio:
        new_width = target_width
        new_height = int(new_width * (img_height / img_width))  # Scale based on width
    else:
        new_height = target_height
        new_width = int(new_height * (img_width / img_height))  # Scale based on height

    # Resize the image to fit into the 2:1 canvas without cutting
    resized_image = cropped_image.resize((new_width, new_height), Image.Resampling.LANCZOS)

    # Create a new blank canvas with the target size
    final_image = Image.new("RGBA", (target_width, target_height), (255, 255, 255, 0))  # Transparent background

    # Calculate the position to paste the resized image in the center
    x_offset = (target_width - new_width) // 2
    y_offset = (target_height - new_height) // 2

    # Paste the resized image onto the canvas
    final_image.paste(resized_image, (x_offset, y_offset))

    # Save the final image as PNG
    final_image.save(output_path, 'PNG')

def shorten_filename(filename, max_length=30):
    """
    Shortens the filename if it's too long, keeping the extension intact.
    """
    name, ext = os.path.splitext(filename)

    # If the filename is longer than the maximum length, truncate it
    if len(name) > max_length:
        name = name[:max_length]

    return f"{name}{ext}"

def batch_process_images(input_directory, output_directory, target_width, target_height):
    # Create the "edited_images" directory if it doesn't exist
    if not os.path.exists(output_directory):
        os.makedirs(output_directory)

    # Track if any image is missed
    missed_images = []

    # Loop through all images in the input directory
    for filename in os.listdir(input_directory):
        if filename.lower().endswith(('.jpg', '.jpeg', '.png')):  # Check image file types
            image_path = os.path.join(input_directory, filename)
            print(f"Processing: {filename}")

            # Remove spaces and make the filename more descriptive
            new_filename = filename.replace(" ", "_")  # Replace spaces with underscores
            new_filename = shorten_filename(new_filename, max_length=30)  # Shorten the filename if necessary

            # Define the output path for each processed image
            output_path = os.path.join(output_directory, new_filename)

            # Process the image (ensure transparency, crop, and resize)
            result = process_image(image_path, output_path, target_width, target_height)

            # If the result is None, the image was skipped
            if result is None:
                missed_images.append(filename)
        else:
            # If the image file doesn't have a valid extension, skip it and log the name
            missed_images.append(filename)

    # Print the missed images if any
    if missed_images:
        print("\nThe following images were skipped:")
        for img in missed_images:
            print(f" - {img}")

# Define the input and output directories
input_directory = './images'  # Input folder where unedited images are stored
output_directory = './edited_images'  # Output folder where edited images will be saved

# Call the function to process images
batch_process_images(input_directory, output_directory, 500, 250)  # 2:1 ratio (400x200)
Enter fullscreen mode Exit fullscreen mode

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

Eliminate Context Switching and Maximize Productivity

Pieces.app

Pieces Copilot is your personalized workflow assistant, working alongside your favorite apps. Ask questions about entire repositories, generate contextualized code, save and reuse useful snippets, and streamline your development process.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay