Created
August 1, 2025 14:49
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
1.png
,2.png
,10.png
) to ensure pairs are formed in a logical order.Requirements
Usage
combine_images.py
.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: