Merge Multiple Images into One: A Complete Guide

17 Jun 2026 1,583 words

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

  1. Drop images or click to browse (min 2 images)
  2. Arrange them by dragging into the desired order
  3. Choose the layout: horizontal, vertical, or grid
  4. Adjust gap and background color
  5. 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.


About this article

Learn how to combine multiple images into a single file. Merge horizontally, vertically, or in a grid online or programmatically with Python and JavaScript.


Related Articles


Related Tools

Help2Code Logo
Menu