"}}]}
← All articles 13 min read

Combine Images: 5 Methods for Any Workflow

Combining images is one of those tasks that sounds simple until you actually need to do it. You have two screenshots that belong in one comparison. A set of product photos that need to form a grid. Before-and-after shots for a case study. Documentation images that make more sense as a single figure than four separate ones.

The challenge is that "combine images" means different things in different contexts. Side-by-side comparison? Vertical stack? A 3x3 grid? An overlay with transparency? Each layout calls for a different approach, and the right tool depends on whether you need a one-off result or a repeatable pipeline.

This guide covers five methods — from quick CLI commands to programmatic approaches — so you can pick the one that fits your workflow and move on.

One thing all methods share: your source images need consistent dimensions before combining. Mismatched sizes produce ugly results with uneven edges and stretched content. Pixotter's resize tool handles this in your browser — drop your images, set matching dimensions, and download them ready to combine. No upload, no account.


Methods Comparison

Not every tool handles every layout. Here is what each method supports and where it runs:

Method Side-by-Side Vertical Stack Grid Overlay Platform Cost
ImageMagick 7.1 Yes Yes Yes Yes Windows, macOS, Linux Free
FFmpeg 7.0 Yes Yes Yes Yes Windows, macOS, Linux Free
Python Pillow 10.4 Yes Yes Yes Yes Any (Python) Free
HTML Canvas Yes Yes Yes Yes Any browser Free
GIMP 2.10.36 Yes Yes Yes Yes Windows, macOS, Linux Free

All five handle every layout type, but the trade-offs are in speed, automation potential, and learning curve. ImageMagick gives you the most flexibility in a single command. Pillow scales to thousands of images with a script. HTML Canvas works without installing anything. GIMP is best when you need visual precision on a single composition. FFmpeg is overkill for still images but useful if you already have it in your pipeline.

Licenses: ImageMagick is Apache 2.0 (free, open source). FFmpeg is LGPL 2.1 for core libraries and GPL 2+ when compiled with certain codecs — check your build. Pillow is HPND (open source, MIT-like). GIMP is GPLv3+. HTML Canvas is a browser-native API, no license applies.


ImageMagick 7.1 is the Swiss Army knife of image manipulation from the command line. If you need to combine images quickly and repeatably, start here.

Install it from imagemagick.org or via your package manager:

# macOS
brew install imagemagick

# Ubuntu/Debian
sudo apt install imagemagick

# Windows (winget)
winget install ImageMagick.ImageMagick

Side by side (horizontal)

The +append operator places images left to right:

magick input1.jpg input2.jpg +append side-by-side.jpg

This works with any number of images. Three images:

magick left.jpg center.jpg right.jpg +append panorama.jpg

Vertical stack

The -append operator stacks images top to bottom:

magick top.jpg bottom.jpg -append stacked.jpg

Useful for combining screenshots into a single scrollable view, or stacking before/after comparisons vertically.

Grid layout with montage

The montage command arranges images into rows and columns:

magick montage img1.jpg img2.jpg img3.jpg img4.jpg \
  -geometry 400x400+10+10 \
  -tile 2x2 \
  grid.jpg

Breaking that down:

Adding gaps and borders

For a clean gap between side-by-side images, use -splice to insert spacing:

magick input1.jpg \
  \( -size 20x1 xc:white \) \
  input2.jpg \
  +append \
  with-gap.jpg

This inserts a 20px-wide white strip between the two images. Change xc:white to xc:black or any hex color (xc:#f0f0f0) for different backgrounds.

For a border around each image before combining:

magick input1.jpg -border 5 -bordercolor "#333333" \
       input2.jpg -border 5 -bordercolor "#333333" \
       +append bordered.jpg

Overlay (composite)

To place one image on top of another — a watermark, a logo, or a picture-in-picture layout:

magick background.jpg overlay.png \
  -gravity southeast \
  -geometry +20+20 \
  -composite \
  result.jpg

The -gravity southeast positions the overlay at the bottom-right corner, offset 20px from each edge. The overlay image should have transparency (PNG with alpha channel) for clean compositing.


Method 2: Python Pillow (Programmatic)

When you need to combine images as part of a script — processing hundreds of product photo pairs, generating comparison grids for a report, or building a CI pipeline that stitches screenshots — Pillow 10.4 is the right choice.

Install it:

pip install Pillow==10.4.0

Side by side

from PIL import Image

def combine_side_by_side(paths, output_path, gap=0, bg_color=(255, 255, 255)):
    """Combine images horizontally with optional gap."""
    images = [Image.open(p) for p in paths]

    # Use the tallest image as the canvas height
    max_height = max(img.height for img in images)
    total_width = sum(img.width for img in images) + gap * (len(images) - 1)

    canvas = Image.new("RGB", (total_width, max_height), bg_color)

    x_offset = 0
    for img in images:
        # Center vertically if heights differ
        y_offset = (max_height - img.height) // 2
        canvas.paste(img, (x_offset, y_offset))
        x_offset += img.width + gap

    canvas.save(output_path, quality=90)
    print(f"Saved: {output_path} ({total_width}x{max_height})")

# Usage
combine_side_by_side(
    ["photo1.jpg", "photo2.jpg", "photo3.jpg"],
    "comparison.jpg",
    gap=20
)

Grid layout

from PIL import Image
import math

def combine_grid(paths, output_path, cols=3, tile_size=(400, 400), gap=10, bg_color=(255, 255, 255)):
    """Arrange images in a grid with uniform tile size."""
    images = [Image.open(p).resize(tile_size, Image.LANCZOS) for p in paths]
    rows = math.ceil(len(images) / cols)

    canvas_w = cols * tile_size[0] + (cols - 1) * gap
    canvas_h = rows * tile_size[1] + (rows - 1) * gap
    canvas = Image.new("RGB", (canvas_w, canvas_h), bg_color)

    for i, img in enumerate(images):
        row, col = divmod(i, cols)
        x = col * (tile_size[0] + gap)
        y = row * (tile_size[1] + gap)
        canvas.paste(img, (x, y))

    canvas.save(output_path, quality=90)
    print(f"Saved: {output_path} ({canvas_w}x{canvas_h})")

# Usage: 3x2 grid of product photos
combine_grid(
    ["prod1.jpg", "prod2.jpg", "prod3.jpg",
     "prod4.jpg", "prod5.jpg", "prod6.jpg"],
    "product-grid.jpg",
    cols=3,
    tile_size=(600, 600),
    gap=15
)

The tile_size parameter forces every image to the same dimensions, which is critical for a clean grid. If your source images are different sizes, resize them to matching dimensions first — Pixotter's batch resize handles this without installing anything.


Method 3: HTML Canvas (Browser-Side)

If you need to combine images inside a web application — no backend, no installs — the HTML Canvas API does the job. This is the same approach Pixotter uses for client-side image processing.

<canvas id="output" style="display:none;"></canvas>

<script>
async function combineImages(urls, direction = "horizontal", gap = 0) {
  const images = await Promise.all(
    urls.map(url => new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    }))
  );

  const canvas = document.getElementById("output");
  const ctx = canvas.getContext("2d");

  if (direction === "horizontal") {
    canvas.width = images.reduce((sum, img) => sum + img.width, 0) + gap * (images.length - 1);
    canvas.height = Math.max(...images.map(img => img.height));
    let x = 0;
    for (const img of images) {
      ctx.drawImage(img, x, (canvas.height - img.height) / 2);
      x += img.width + gap;
    }
  } else {
    canvas.width = Math.max(...images.map(img => img.width));
    canvas.height = images.reduce((sum, img) => sum + img.height, 0) + gap * (images.length - 1);
    let y = 0;
    for (const img of images) {
      ctx.drawImage(img, (canvas.width - img.width) / 2, y);
      y += img.height + gap;
    }
  }

  // Export as blob
  canvas.toBlob(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "combined.jpg";
    a.click();
    URL.revokeObjectURL(url);
  }, "image/jpeg", 0.9);
}
</script>

This runs entirely in the browser. No server roundtrip, no file uploads. The main limitation is memory — combining many large images (20+ at 4000px each) can hit browser memory limits. For those cases, resize your source images down first.


Method 4: FFmpeg (CLI)

FFmpeg 7.0 is primarily a video tool, but its filter system handles image combining through the hstack, vstack, and xstack filters.

Side by side

ffmpeg -i left.jpg -i right.jpg \
  -filter_complex hstack=inputs=2 \
  side-by-side.jpg

Vertical stack

ffmpeg -i top.jpg -i bottom.jpg \
  -filter_complex vstack=inputs=2 \
  stacked.jpg

2x2 grid

ffmpeg -i img1.jpg -i img2.jpg -i img3.jpg -i img4.jpg \
  -filter_complex "[0][1]hstack=inputs=2[top];[2][3]hstack=inputs=2[bottom];[top][bottom]vstack=inputs=2" \
  grid.jpg

FFmpeg works well if it is already in your toolchain. For image-only workflows, ImageMagick is more intuitive. FFmpeg shines when you are combining images into video frames or need to apply the same filters you use for video processing.


Method 5: GIMP (GUI)

GIMP 2.10.36 is the manual-precision option. Use it when you need pixel-perfect placement, blending modes, or visual adjustments that CLI tools cannot easily express.

  1. Open GIMP. Go to File > Open as Layers and select all images you want to combine.
  2. Each image loads as a separate layer. Go to Image > Canvas Size and increase the canvas to fit your desired layout (e.g., double the width for side-by-side).
  3. Use the Move tool (M) to position each layer where you want it.
  4. For precise alignment: Image > Guides > New Guide (By Percent) at 50% to mark the center.
  5. When satisfied, go to Image > Flatten Image to merge all layers.
  6. Export via File > Export As and choose your output format.

GIMP also supports Script-Fu and Python-Fu for batch operations, but if you are scripting, Pillow or ImageMagick are simpler choices.


Preparing Images Before Combining

The single biggest factor in a clean combined image is matching dimensions. When images have different sizes, you get one of three bad outcomes:

Fix this before combining:

  1. Decide your target dimensions. For side-by-side comparisons, all images should have the same height. For grids, all images should be the same width and height. For vertical stacks, match the width.

  2. Resize to matching dimensions. Pixotter's resize tool handles this in a few seconds — drop your images, set the target dimensions, toggle "maintain aspect ratio" if you want proportional scaling. Everything processes in your browser.

  3. Crop to matching aspect ratios. If your images have different aspect ratios and you need exact matching, crop them first. A 16:9 image next to a 4:3 image will look off even if heights match.

  4. Convert to the same format. Mixing PNG and JPEG sources can cause color space mismatches. Pick one format for your source images. Pixotter's converter handles batch format conversion without quality loss.

This preparation step takes 30 seconds and makes the difference between a professional result and an obviously cobbled-together image.


Optimizing the Combined Image

Combined images are large. Stitching two 2MB photos side by side does not produce a 4MB result — it is often larger because the combined image has more pixels and the compression algorithm has more data to encode. A 2x3 grid of product photos can easily hit 8-10MB.

That is too large for the web, email, or most upload forms. Compress after combining:

Run your combined image through Pixotter's compressor before publishing. It strips metadata, optimizes encoding, and reduces file size — all in your browser, no upload required. A 6MB combined JPEG typically compresses to under 2MB at quality 80 with no visible difference.


Common Use Cases

Before-and-after comparisons

Side-by-side is the standard layout. Resize both images to identical dimensions, combine horizontally with a thin separator:

magick before.jpg \( -size 4x1 xc:#cccccc \) after.jpg +append comparison.jpg

The 4px gray line between images makes the boundary clear without being distracting.

Social media grids

Instagram carousels and Pinterest collages use specific aspect ratios. For a 2x2 Instagram grid (1080x1080 total):

magick montage img1.jpg img2.jpg img3.jpg img4.jpg \
  -geometry 530x530+10+10 \
  -tile 2x2 \
  -background white \
  instagram-grid.jpg

Each tile is 530px with 10px gaps, fitting neatly into a 1080x1080 square. Resize your source images to square aspect ratios first using Pixotter's crop tool.

Documentation and tutorials

Vertical stacking works well for step-by-step screenshots:

magick step1.png step2.png step3.png -append tutorial-steps.png

This produces a single tall image showing the progression. Save as PNG to preserve text sharpness in the screenshots.

Product photo collages

E-commerce listings often show multiple angles in a single image. A 3-column layout works well:

magick montage front.jpg side.jpg back.jpg detail1.jpg detail2.jpg detail3.jpg \
  -geometry 600x600+8+8 \
  -tile 3x \
  -background white \
  product-collage.jpg

The -tile 3x flag means 3 columns, as many rows as needed. Batch resize your product photos to square dimensions before running this command for consistent results.


FAQ

How do I combine two images side by side?

The fastest method is ImageMagick's +append operator: magick image1.jpg image2.jpg +append output.jpg. This places images left to right. For vertical stacking, use -append instead. Both images should have matching heights (for horizontal) or matching widths (for vertical) to avoid uneven edges. Resize them to matching dimensions first if needed.

Can I combine images without installing software?

Yes. The HTML Canvas API in any modern browser can combine images with JavaScript — no installs, no uploads, no server. The code example in this article runs entirely client-side. For preparing images before combining (resizing, cropping, format conversion), Pixotter does all of that in-browser too.

How do I merge images into a grid?

ImageMagick's montage command is the most flexible option: magick montage *.jpg -geometry 400x400+10+10 -tile 3x3 grid.jpg. This creates a 3x3 grid with 400px tiles and 10px gaps. Python Pillow's approach (shown above) gives you more control when scripting. For consistent results, resize all images to identical dimensions before creating the grid.

What is the best format for combined images?

It depends on the content. JPEG at quality 80-85 for photographs and photo collages. PNG for screenshots, diagrams, or any image with text. WebP for the best compression-to-quality ratio when your platform supports it (97% of browsers do). Avoid combining into BMP or TIFF for web use — the files will be enormous.

How do I add space between combined images?

In ImageMagick, insert a colored spacer between images: magick img1.jpg \( -size 20x1 xc:white \) img2.jpg +append output.jpg. The 20x1 creates a 20px-wide white gap. In Python Pillow, use the gap parameter in the combine_side_by_side function from this article. For montage grids, the +10+10 in -geometry controls horizontal and vertical spacing.

How do I combine images of different sizes?

First, decide what "different sizes" means for your layout. If heights differ for a side-by-side layout, the result will have uneven edges. The clean approach: resize all images to matching dimensions before combining. If you cannot resize, ImageMagick's append will use the largest dimension and leave whitespace. Pillow's example above centers smaller images vertically. The best results always come from consistent source dimensions.