Merge Multiple Images into One: A Complete Guide
Combining multiple images into a single file is a common task for creating comparison collages, social media graphics, before-and-after photos, contact sheets, and documentation visuals. Whether you need to merge images side by side, stack them vertically, or arrange them in a grid, there are tools and libraries that make it simple.
Why Merge Images?
- Before/after comparisons — Show transformation in a single frame
- Social media collages — Combine multiple photos into one post
- Contact sheets — Preview many images at a glance
- Documentation — Show screenshots side by side for tutorials
- Panoramas — Stitch overlapping photos (requires blending)
- Side-by-side comparisons — Compare two versions of a design
Merger Layouts
Horizontal Merge
Images are placed left to right, all at the same height:
┌──────┬──────┬──────┐
│ img1 │ img2 │ img3 │
└──────┴──────┴──────┘
Best for: before/after comparisons, image sequences
Vertical Merge
Images are stacked top to bottom, all at the same width:
┌──────────┐
│ img1 │
├──────────┤
│ img2 │
├──────────┤
│ img3 │
└──────────┘
Best for: scrolling presentations, mobile screenshots
Grid Merge
Images arranged in rows and columns:
┌──────┬──────┬──────┐
│ img1 │ img2 │ img3 │
├──────┼──────┼──────┤
│ img4 │ img5 │ img6 │
└──────┴──────┴──────┘
Best for: photo collages, contact sheets, portfolios
Online Image Merger
The Image Merger tool on Help2Code lets you combine multiple images directly in your browser — no uploads, all processing is client-side.
Features
- Horizontal merge — align images side by side
- Vertical merge — stack images vertically
- Grid layout — arrange in configurable rows and columns
- Custom gap — set spacing between images (in pixels)
- Background color — choose the canvas background
- Drag to reorder — rearrange images before merging
- Output formats — PNG, JPEG, WebP
- 100% client-side — your images never leave your device
How to Use
- Drop images or click to browse (min 2 images)
- Arrange them by dragging into the desired order
- Choose the layout: horizontal, vertical, or grid
- Adjust gap and background color
- Click merge and download the result
Code Examples
Python: Merge Images Horizontally with Pillow
from PIL import Image
def merge_horizontal(image_paths: list[str], output_path: str, gap: int = 10):
images = [Image.open(p) for p in image_paths]
widths, heights = zip(*(img.size for img in images))
total_width = sum(widths) + gap * (len(images) - 1)
max_height = max(heights)
canvas = Image.new('RGB', (total_width, max_height), (255, 255, 255))
x_offset = 0
for img in images:
canvas.paste(img, (x_offset, (max_height - img.height) // 2))
x_offset += img.width + gap
canvas.save(output_path)
merge_horizontal(['img1.jpg', 'img2.jpg', 'img3.jpg'], 'merged.jpg')
Python: Merge Vertically
from PIL import Image
def merge_vertical(image_paths: list[str], output_path: str, gap: int = 10):
images = [Image.open(p) for p in image_paths]
widths, heights = zip(*(img.size for img in images))
total_height = sum(heights) + gap * (len(images) - 1)
max_width = max(widths)
canvas = Image.new('RGB', (max_width, total_height), (255, 255, 255))
y_offset = 0
for img in images:
canvas.paste(img, ((max_width - img.width) // 2, y_offset))
y_offset += img.height + gap
canvas.save(output_path)
merge_vertical(['img1.jpg', 'img2.jpg'], 'stacked.jpg')
Python: Merge in a Grid
from PIL import Image
def merge_grid(image_paths: list[str], output_path: str,
cols: int = 3, gap: int = 10, bg_color: str = '#ffffff'):
images = [Image.open(p) for p in image_paths]
rows = (len(images) + cols - 1) // cols
cell_w = max(img.width for img in images)
cell_h = max(img.height for img in images)
canvas_w = cell_w * cols + gap * (cols - 1)
canvas_h = cell_h * rows + gap * (rows - 1)
canvas = Image.new('RGB', (canvas_w, canvas_h), bg_color)
for i, img in enumerate(images):
r, c = i // cols, i % cols
x = c * (cell_w + gap) + (cell_w - img.width) // 2
y = r * (cell_h + gap) + (cell_h - img.height) // 2
canvas.paste(img, (x, y))
canvas.save(output_path)
merge_grid(['img1.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg'], 'grid.jpg', cols=2)
JavaScript (Node.js): Merge with Sharp
const sharp = require('sharp');
async function mergeHorizontal(inputs, output, gap = 10) {
const images = await Promise.all(
inputs.map(src => sharp(src).metadata().then(meta => ({ src, meta })))
);
const maxHeight = Math.max(...images.map(i => i.meta.height));
const totalWidth = images.reduce((sum, i) => sum + i.meta.width, 0) + gap * (images.length - 1);
const compositeOps = [];
let left = 0;
for (const { src, meta } of images) {
const top = Math.round((maxHeight - meta.height) / 2);
compositeOps.push({ input: src, top, left });
left += meta.width + gap;
}
await sharp({
create: {
width: totalWidth,
height: maxHeight,
channels: 3,
background: { r: 255, g: 255, b: 255 }
}
}).composite(compositeOps).toFile(output);
}
mergeHorizontal(['img1.jpg', 'img2.jpg'], 'merged.jpg');
PHP: Merge Images with GD
function mergeImages(array $inputPaths, string $outputPath, string $direction = 'horizontal', int $gap = 10): void {
$images = array_map(function ($path) {
$img = imagecreatefromstring(file_get_contents($path));
return ['img' => $img, 'w' => imagesx($img), 'h' => imagesy($img)];
}, $inputPaths);
if ($direction === 'horizontal') {
$canvasW = array_sum(array_column($images, 'w')) + $gap * (count($images) - 1);
$canvasH = max(array_column($images, 'h'));
$canvas = imagecreatetruecolor($canvasW, $canvasH);
imagefill($canvas, 0, 0, imagecolorallocate($canvas, 255, 255, 255));
$x = 0;
foreach ($images as $img) {
imagecopy($canvas, $img['img'], $x, intval(($canvasH - $img['h']) / 2), 0, 0, $img['w'], $img['h']);
$x += $img['w'] + $gap;
}
} else {
$canvasW = max(array_column($images, 'w'));
$canvasH = array_sum(array_column($images, 'h')) + $gap * (count($images) - 1);
$canvas = imagecreatetruecolor($canvasW, $canvasH);
imagefill($canvas, 0, 0, imagecolorallocate($canvas, 255, 255, 255));
$y = 0;
foreach ($images as $img) {
imagecopy($canvas, $img['img'], intval(($canvasW - $img['w']) / 2), $y, 0, 0, $img['w'], $img['h']);
$y += $img['h'] + $gap;
}
}
imagejpeg($canvas, $outputPath, 95);
imagedestroy($canvas);
array_walk($images, fn($i) => imagedestroy($i['img']));
}
mergeImages(['img1.jpg', 'img2.jpg'], 'merged.jpg', 'horizontal');
Command Line: ImageMagick
# Horizontal merge
convert img1.jpg img2.jpg img3.jpg +append merged.jpg
# Vertical merge
convert img1.jpg img2.jpg img3.jpg -append stacked.jpg
# Grid merge (2 columns)
montage img1.jpg img2.jpg img3.jpg img4.jpg -tile 2x2 -geometry +10+10 grid.jpg
# With resize to uniform dimensions
convert img1.jpg img2.jpg -resize x800 +append merged.jpg
Creating a Before/After Comparison
from PIL import Image
def before_after(before_path: str, after_path: str, output_path: str, label: bool = True):
before = Image.open(before_path)
after = Image.open(after_path)
# Ensure same height
target_h = min(before.height, after.height)
before = before.resize((int(before.width * target_h / before.height), target_h))
after = after.resize((int(after.width * target_h / after.height), target_h))
# Horizontal merge with a split line
canvas = Image.new('RGB', (before.width + 2 + after.width, target_h + 40), (255, 255, 255))
canvas.paste(before, (0, 20))
canvas.paste(after, (before.width + 2, 20))
canvas.save(output_path)
before_after('original.jpg', 'edited.jpg', 'comparison.jpg')
Merging with Alpha Transparency
When merging PNG images with transparent backgrounds, ensure the canvas supports alpha:
from PIL import Image
def merge_with_alpha(image_paths, output_path, direction='horizontal', gap=10):
images = [Image.open(p).convert('RGBA') for p in image_paths]
if direction == 'horizontal':
total_w = sum(img.width for img in images) + gap * (len(images) - 1)
max_h = max(img.height for img in images)
canvas = Image.new('RGBA', (total_w, max_h), (0, 0, 0, 0))
x = 0
for img in images:
canvas.paste(img, (x, (max_h - img.height) // 2), img)
x += img.width + gap
else:
max_w = max(img.width for img in images)
total_h = sum(img.height for img in images) + gap * (len(images) - 1)
canvas = Image.new('RGBA', (max_w, total_h), (0, 0, 0, 0))
y = 0
for img in images:
canvas.paste(img, ((max_w - img.width) // 2, y), img)
y += img.height + gap
canvas.save(output_path)
merge_with_alpha(['icon1.png', 'icon2.png'], 'combined.png')
Batch Processing
Create Contact Sheets
from PIL import Image
from pathlib import Path
def create_contact_sheet(directory: str, output: str, cols: int = 4, thumb_size: tuple = (200, 200)):
paths = sorted(Path(directory).glob('*.jpg'))
thumbs = []
for path in paths:
with Image.open(path) as img:
img.thumbnail(thumb_size)
thumbs.append(img.copy())
rows = (len(thumbs) + cols - 1) // cols
gap = 10
cell_w = max(t.width for t in thumbs)
cell_h = max(t.height for t in thumbs)
sheet_w = cell_w * cols + gap * (cols - 1)
sheet_h = cell_h * rows + gap * (rows - 1)
sheet = Image.new('RGB', (sheet_w, sheet_h), (255, 255, 255))
for i, thumb in enumerate(thumbs):
r, c = i // cols, i % cols
x = c * (cell_w + gap) + (cell_w - thumb.width) // 2
y = r * (cell_h + gap) + (cell_h - thumb.height) // 2
sheet.paste(thumb, (x, y))
sheet.save(output)
create_contact_sheet('photos/', 'contact-sheet.jpg', cols=5)
ImageMagick: Create a Contact Sheet
montage *.jpg -tile 5x -geometry 200x200+5+5 contact-sheet.jpg
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Images have different heights | All images must share the same height for horizontal merge | Resize to uniform height first |
| Large output file | Merging many large images creates a huge canvas | Resize images before merging |
| Color mismatch | Different color profiles (sRGB vs Adobe RGB) | Convert all to sRGB before merging |
| Memory error | Too many images or too large | Batch in smaller groups |
| Gap looks uneven | Images have different dimensions | Use grid layout with uniform cell size |
Privacy and Security
The Image Merger tool processes everything in your browser — your images are never uploaded. For automated or batch merging, use the code examples above with your local image library.
Conclusion
Merging images into a single file is useful for comparisons, collages, contact sheets, and documentation. Whether you use the Image Merger tool for quick browser-based merging or automate the process with Python or JavaScript, combining images is a straightforward but powerful technique for visual communication.