Skip to content

Instantly share code, notes, and snippets.

@maaduukaar
Created August 1, 2025 14:49
Show Gist options
  • Save maaduukaar/eabe9a376f980c29ffd6e6fd55275c5a to your computer and use it in GitHub Desktop.
Save maaduukaar/eabe9a376f980c29ffd6e6fd55275c5a to your computer and use it in GitHub Desktop.
A Python script to combine multiple images onto a single A4 page, useful for printing. Supports various layouts: 2 or 4 images per page, in both horizontal and vertical orientations. Features natural sorting for filenames and an interactive confirmation prompt.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
from PIL import Image
import argparse
from pathlib import Path
import re
def natural_sort_key(s):
"""
Key for natural sorting of strings with numbers.
e.g. "1.png", "2.png", "10.png" instead of "1.png", "10.png", "2.png"
"""
return [int(text) if text.isdigit() else text.lower()
for text in re.split(r'(\d+)', str(s))]
def combine_images(input_folder, output_folder="done", four_images=False, vertical_layout=False):
"""
Combines multiple images onto a single A4 sheet.
Args:
input_folder: Path to folder with input images.
output_folder: Path to output folder (default: "done").
four_images: If True, place 4 images per page instead of 2.
vertical_layout: If True, use a vertical A4 sheet for horizontal images.
"""
if four_images and vertical_layout:
print("Error: The --four and --vertical parameters cannot be used at the same time.")
return
# Create output directory if it doesn't exist
output_path = Path(output_folder)
output_path.mkdir(exist_ok=True)
# Get all image files
image_extensions = ['.jpg', '.jpeg', '.png', '.tiff', '.tif']
image_files = []
for ext in image_extensions:
image_files.extend(list(Path(input_folder).glob(f'*{ext}')))
image_files.extend(list(Path(input_folder).glob(f'*{ext.upper()}')))
# Remove duplicates and use "natural" sorting
image_files = sorted(list(set(image_files)), key=lambda x: natural_sort_key(x.name))
total_files = len(image_files)
print(f"Found {total_files} images")
# Print the list of all files for verification
print("List of all files:")
for i, img_file in enumerate(image_files):
print(f" {i+1}. {img_file.name}")
# Determine groups for combining
groups = []
images_per_page = 4 if four_images else 2
for i in range(0, total_files, images_per_page):
groups.append(image_files[i:i + images_per_page])
# Print the list of groups for verification
print(f"\nGroups to be combined ({images_per_page} per page):")
for i, group in enumerate(groups):
names = ' + '.join([img.name for img in group])
print(f" Group {i+1}: {names}")
# Request confirmation
confirm = input("\nContinue with these groups? (y/n): ")
if confirm.lower() != 'y':
print("Operation cancelled by user.")
return
# Image combination process
for idx, image_group in enumerate(groups):
if vertical_layout:
# Vertical A4 sheet (portrait)
combined = Image.new('RGB', (2480, 3508), (255, 255, 255))
# Two horizontal A5 areas
max_width, max_height = 2480, 1754
positions = [(0, 0), (0, max_height)]
else:
# Horizontal A4 sheet (landscape)
combined = Image.new('RGB', (3508, 2480), (255, 255, 255))
if four_images:
# Logic for 4 images (A6)
max_width, max_height = 1754, 1240 # Quadrant size for A6
positions = [
(0, 0), (max_width, 0),
(0, max_height), (max_width, max_height)
]
else:
# Logic for 2 images (A5)
max_width, max_height = 1748, 2480
positions = [(0, 0), (max_width, 0)]
for i, img_path in enumerate(image_group):
img = Image.open(img_path)
# Resize image
width, height = img.size
ratio = min(max_width / width, max_height / height)
new_width = int(width * ratio)
new_height = int(height * ratio)
img_resized = img.resize((new_width, new_height), Image.LANCZOS)
# Position image
pos_x, pos_y = positions[i]
paste_x = pos_x + (max_width - new_width) // 2
paste_y = pos_y + (max_height - new_height) // 2
combined.paste(img_resized, (paste_x, paste_y))
# Save the combined image
output_filename = f"{output_path}/combined_{idx + 1}.jpg"
combined.save(output_filename, quality=95, dpi=(300, 300))
group_names = ' + '.join([p.name for p in image_group])
print(f"Combined: {group_names} -> {output_filename}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Combine images onto A4 sheets.')
parser.add_argument('input_folder', help='Folder containing input images.')
parser.add_argument('--output_folder', default='done', help='Output folder for combined images.')
parser.add_argument('--four', action='store_true', help='Place 4 images per page (A6 format).')
parser.add_argument('-v', '--vertical', action='store_true', help='Stack images on a vertical sheet.')
args = parser.parse_args()
combine_images(args.input_folder, args.output_folder, args.four, args.vertical)
print("All images processed successfully!")
@maaduukaar
Copy link
Author

Image Combination Script

This Python script automatically combines multiple images into a single A4 sheet, which is convenient for printing. The script supports various layout modes: 2 or 4 images per page, in both horizontal and vertical orientations.

Key Features

  • Combine 2 Images: Places two images side-by-side on a horizontal A4 sheet (each in an A5-sized area).
  • Combine 4 Images: Arranges four images in a 2x2 grid on a horizontal A4 sheet (each in an A6-sized area).
  • Vertical Layout: Places two images on top of each other on a vertical A4 sheet.
  • Natural Sorting: Correctly sorts files with numbers in their names (e.g., 1.png, 2.png, 10.png) to ensure pairs are formed in a logical order.
  • Interactive Confirmation: Before processing, the script shows which files will be grouped and asks for user confirmation.
  • Handles Odd Numbers: If there's a leftover image without a pair, it will be placed on a separate sheet.

Requirements

  • Python 3
  • Pillow library:
    pip install Pillow

Usage

  1. Save the script as combine_images.py.
  2. Place all the images you want to combine into a single folder.
  3. Open your terminal or command prompt and run the command with the desired mode.

Command Examples

  • Default mode (2 images on a horizontal sheet):

    python combine_images.py "path/to/your/folder"
  • 4-image mode:

    python combine_images.py "path/to/your/folder" --four
  • Vertical mode (2 images stacked):

    python combine_images.py "path/to/your/folder" --vertical
  • Specifying an output folder:

    python combine_images.py "path/to/your/folder" --output_folder "finished_files"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment