Skip to content

Instantly share code, notes, and snippets.

@jshakes
Last active March 17, 2025 13:12
Show Gist options
  • Save jshakes/60a94240b4a27c91533b43a6f75b30fc to your computer and use it in GitHub Desktop.
Save jshakes/60a94240b4a27c91533b43a6f75b30fc to your computer and use it in GitHub Desktop.
Bulk image padding for client logo grids

pad_images.py

A Python script to pad images to match a specified aspect ratio while ensuring a minimum amount of padding around the image relative to its size. It supports multiple image formats and preserves transparency for PNG, GIF, and WEBP files.

Note the script does not resize images, it will only add padding as needed.

Features

  • Maintains the specified aspect ratio (e.g., 4:3, 16:9) across all images.
  • Ensures a minimum padding percentage based on the largest image dimension.
  • Supports PNG transparency; other formats get a white background.
  • Works with common image formats (.png, .jpg, .jpeg, .bmp, .gif, .webp).

Installation

Ensure you have Python installed along with Pillow:

pip install pillow

Usage

Run the script with:

python pad_images.py <input_dir> <aspect_ratio> <min_padding_percent> <output_dir>
  • <input_dir>: Directory containing images to be processed.
  • <aspect_ratio>: Desired aspect ratio (e.g., 4:3, 16:9).
  • <min_padding_percent>: Minimum padding percentage relative to the largest dimension.
  • <output_dir>: Directory where padded images will be saved.

Example

python pad_images.py images/ 16:9 10 padded_images/

This processes all images in images/, adds at least 10% padding, and saves the results in padded_images/.

#!/usr/bin/env python3
import os
import sys
from PIL import Image
def pad_image(
input_path: str, ratio_str: str, min_padding_percent: float, output_path: str
):
"""
Pad a single image to match a given aspect ratio, ensuring
at least 'min_padding_percent' of the largest original dimension
is added as padding on each side. PNG images are padded with
transparent pixels; other formats are padded with white.
"""
# Parse the aspect ratio, e.g. '4:3' -> w_ratio=4, h_ratio=3
w_ratio_str, h_ratio_str = ratio_str.split(":")
w_ratio = float(w_ratio_str)
h_ratio = float(h_ratio_str)
# Open the original image
with Image.open(input_path) as im:
original_mode = im.mode
original_width, original_height = im.size
# Determine required padding in pixels based on the longest edge
longest_edge = max(original_width, original_height)
min_pad = int(round((longest_edge * min_padding_percent) / 100.0))
# Minimum required final dimensions:
min_final_width = original_width + 2 * min_pad
min_final_height = original_height + 2 * min_pad
# The final image must have an aspect ratio = w_ratio / h_ratio
# We find the smallest W x H that satisfies:
# W / H = (w_ratio / h_ratio),
# W >= min_final_width,
# H >= min_final_height.
# Start by matching min_final_width
final_width = min_final_width
# Derive final_height from ratio
final_height = int(round(final_width * (h_ratio / w_ratio)))
# If final_height is too small, bump it up and recalc final_width
if final_height < min_final_height:
final_height = min_final_height
final_width = int(round(final_height * (w_ratio / h_ratio)))
# Decide on the background:
# If the output format will be PNG, we can preserve transparency;
# otherwise we'll use white.
ext = os.path.splitext(input_path)[1].lower()
if ext in (".png", ".gif", ".webp"):
# RGBA with alpha channel for transparent padding
mode = "RGBA"
background_color = (0, 0, 0, 0) # fully transparent
else:
# RGB with white background
mode = "RGB"
background_color = (255, 255, 255)
# Create new image for the padded result
new_im = Image.new(mode, (final_width, final_height), background_color)
# Compute top-left corner at which to paste the original
x_offset = (final_width - original_width) // 2
y_offset = (final_height - original_height) // 2
# Convert original if needed (e.g., if new_im is RGBA and original is RGB)
if mode == "RGBA" and im.mode != "RGBA":
im = im.convert("RGBA")
elif mode == "RGB" and im.mode not in ("RGB", "L"):
im = im.convert("RGB")
# Paste original image into the padded (centered) area
new_im.paste(im, (x_offset, y_offset))
# Save the image to the output path
new_im.save(output_path)
def main():
if len(sys.argv) != 5:
print(
"Usage: python pad_images.py <input_dir> <aspect_ratio> <min_padding_percent> <output_dir>"
)
sys.exit(1)
input_dir = sys.argv[1]
aspect_ratio = sys.argv[2] # e.g. '4:3'
min_padding = float(sys.argv[3]) # e.g. 10
output_dir = sys.argv[4]
# Create output directory if necessary
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Loop over all files in the input directory
for filename in os.listdir(input_dir):
# Only consider files with typical image extensions
if filename.lower().endswith(
(".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp")
):
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir, filename)
try:
pad_image(input_path, aspect_ratio, min_padding, output_path)
print(f"Padded image saved: {output_path}")
except Exception as e:
print(f"Error processing {input_path}: {e}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment