When working with image processing in .NET, a common need is to merge multiple images—often of different sizes—into a single output using Aspose.Imaging combine multiple images. Typical use cases include collages, sprite sheets, contact sheets, or marketing banners. This tutorial shows how to merge images using Aspose.Imaging for .NET, a C# image collage Aspose.Imaging, with precise control over layout: axis (horizontal/vertical), alignment (top/center/bottom and left/center/right), outer padding (image alignment padding .NET), merge images with padding C#, and spacing between images. We’ll also cover a safe, cross-platform approach that relies on Aspose’s Graphics API.

What You’ll Build

  • Layout: horizontal or vertical

  • Alignment:

    • Horizontal layout → vertical alignment: Top, Middle, Bottom
    • Vertical layout → horizontal alignment: Left, Center, Right
  • Padding: outer padding and inter-item spacing

  • Background: solid color fill

  • Formats: load mixed formats (JPG, PNG, etc.), save to PNG/JPEG


Complete Example

using System;
using System.Collections.Generic;
using System.IO;
using Aspose.Imaging;
using Aspose.Imaging.ImageOptions;

namespace ImagingMergeDemo
{
    public enum MergeAxis { Horizontal, Vertical }
    public enum VAlign { Top, Middle, Bottom }
    public enum HAlign { Left, Center, Right }

    public static class ImageMerger
    {
        /// <summary>
        /// Merges input images into a single image with alignment and padding using Aspose.Imaging merge images .NET.
        /// </summary>
        /// <param name="inputPaths">List of source image file paths.</param>
        /// <param name="axis">Horizontal or Vertical stacking.</param>
        /// <param name="outerPadding">Padding around the whole collage (in pixels).</param>
        /// <param name="spacing">Spacing between images (in pixels).</param>
        /// <param name="bgColor">Background color for the canvas.</param>
        /// <param name="verticalAlign">Only used when axis == Horizontal (Top/Middle/Bottom inside the row).</param>
        /// <param name="horizontalAlign">Only used when axis == Vertical (Left/Center/Right inside the column).</param>
        /// <param name="outputPath">Destination file path. Extension determines encoder (e.g., .png, .jpg).</param>
        public static void Merge(
            IReadOnlyList<string> inputPaths,
            MergeAxis axis,
            int outerPadding,
            int spacing,
            Color bgColor,
            VAlign verticalAlign,
            HAlign horizontalAlign,
            string outputPath)
        {
            if (inputPaths is null || inputPaths.Count == 0)
                throw new ArgumentException("No input images provided.");

            // Load all images first so we can compute canvas size.
            var loaded = new List<Image>(inputPaths.Count);
            try
            {
                foreach (var p in inputPaths)
                {
                    var img = Image.Load(p);
                    loaded.Add(img);
                }

                // Compute canvas size.
            // For horizontal axis: width = sum(widths) + spacings + 2*outerPadding
            // height = max(heights) + 2*outerPadding
            // For vertical axis:   height = sum(heights) + spacings + 2*outerPadding
            // width  = max(widths) + 2*outerPadding
            int totalWidth, totalHeight;

            if (axis == MergeAxis.Horizontal)
            {
                int sumWidths = 0, maxH = 0;
                for (int i = 0; i < loaded.Count; i++)
                {
                    sumWidths += loaded[i].Width;
                    maxH = Math.Max(maxH, loaded[i].Height);
                }
                totalWidth = sumWidths + ((loaded.Count - 1) * spacing) + 2 * outerPadding;
                totalHeight = maxH + 2 * outerPadding;
            }
            else
            {
                int sumHeights = 0, maxW = 0;
                for (int i = 0; i < loaded.Count; i++)
                {
                    sumHeights += loaded[i].Height;
                    maxW = Math.Max(maxW, loaded[i].Width);
                }
                totalHeight = sumHeights + ((loaded.Count - 1) * spacing) + 2 * outerPadding;
                totalWidth = maxW + 2 * outerPadding;
            }

            // Create canvas (use PNG by default for lossless output; you can switch to JPEGOptions)
            using var canvas = Image.Create(new PngOptions(), totalWidth, totalHeight);

            // Draw on canvas
            using var g = new Graphics(canvas);
            g.Clear(bgColor);

            int cursorX = outerPadding;
            int cursorY = outerPadding;

            for (int i = 0; i < loaded.Count; i++)
            {
                var img = loaded[i];

                int drawX, drawY;

                if (axis == MergeAxis.Horizontal)
                {
                    // X flows left -> right
                    drawX = cursorX;

                    // Y depends on vertical alignment vs tallest height
                    drawY = verticalAlign switch
                    {
                        VAlign.Top    => outerPadding,
                        VAlign.Middle => outerPadding + (totalHeight - 2 * outerPadding - img.Height) / 2,
                        VAlign.Bottom => outerPadding + (totalHeight - 2 * outerPadding - img.Height),
                        _ => outerPadding
                    };

                    // Draw and move X cursor
                    g.DrawImage(img, new Rectangle(drawX, drawY, img.Width, img.Height));
                    cursorX += img.Width + spacing;
                }
                else
                {
                    // Y flows top -> bottom
                    drawY = cursorY;

                    // X depends on horizontal alignment vs widest width
                    drawX = horizontalAlign switch
                    {
                        HAlign.Left   => outerPadding,
                        HAlign.Center => outerPadding + (totalWidth - 2 * outerPadding - img.Width) / 2,
                        HAlign.Right  => outerPadding + (totalWidth - 2 * outerPadding - img.Width),
                        _ => outerPadding
                    };

                    // Draw and move Y cursor
                    g.DrawImage(img, new Rectangle(drawX, drawY, img.Width, img.Height));
                    cursorY += img.Height + spacing;
                }
            }

            // Save with encoder that matches extension
            SaveByExtension(canvas, outputPath);
        }
        finally
        {
            // Dispose loaded images
            foreach (var img in loaded)
                img.Dispose();
        }
    }

    private static void SaveByExtension(Image image, string outputPath)
    {
        var ext = Path.GetExtension(outputPath).ToLowerInvariant();
        ImageOptionsBase opts = ext switch
        {
            ".jpg" or ".jpeg" => new JpegOptions { Quality = 90 },
            ".png"            => new PngOptions(),
            _                 => new PngOptions() // default to PNG
        };
        image.Save(outputPath, opts);
    }
}

// Example usage
public class Program
{
    public static void Main()
    {
        var inputs = new List<string>
        {
            "image1.jpg",
            "image2.png",
            "image3.jpg"
        };

        // Horizontal strip, vertically centered, with padding/spacing
        ImageMerger.Merge(
            inputPaths: inputs,
            axis: MergeAxis.Horizontal,
            outerPadding: 20,
            spacing: 10,
            bgColor: Color.White,
            verticalAlign: VAlign.Middle,
            horizontalAlign: HAlign.Center, // ignored for horizontal axis
            outputPath: "merged_horizontal.png"
        );

        // Vertical stack, horizontally right-aligned
        ImageMerger.Merge(
            inputPaths: inputs,
            axis: MergeAxis.Vertical,
            outerPadding: 20,
            spacing: 12,
            bgColor: Color.FromArgb(255, 245, 245, 245),
            verticalAlign: VAlign.Middle,    // ignored for vertical axis
            horizontalAlign: HAlign.Right,
            outputPath: "merged_vertical.jpg"
        );
    }
}

}


## Step-by-Step Guide

### Step 1: Load Images

Load all input images with `Image.Load(path)`. Keep them alive until after drawing, then dispose.

### Step 2: Determine Output Size

* **Horizontal layout**: width = sum of widths + spacings + outer padding; height = max height + outer padding.
* **Vertical layout**: height = sum of heights + spacings + outer padding; width = max width + outer padding.

### Step 3: Create the Output Canvas

Create using `Image.Create(new PngOptions(), width, height)` (or `JpegOptions` if you prefer lossy output). Clear with a background color.

### Step 4: Configure Alignment & Padding

* Horizontal merge → calculate Y by `Top / Middle / Bottom`.
* Vertical merge → calculate X by `Left / Center / Right`.
* Apply `outerPadding` and `spacing` consistently.

### Step 5: Draw Each Image

Use `Graphics.DrawImage(image, new Rectangle(x, y, image.Width, image.Height))`.

### Step 6: Save the Result

Pick the encoder based on output filename extension (e.g., `.png` → `PngOptions`, `.jpg` → `JpegOptions { Quality = … }`).

---

## Best Practices

* **Normalize formats**: If you need transparent backgrounds, save as PNG. For smaller files without transparency, use JPEG and tune `Quality`.
* **Guardrails**: Validate input list, handle missing files, and consider maximum canvas dimensions to avoid OOM.
* **Dispose**: `Image`, `Graphics` are disposable—use `using` or `try/finally`.
* **Color consistency**: If inputs have mixed color types, rely on Aspose defaults, or explicitly convert when needed.
* **Batching**: For large sets, stream outputs as you go or create multiple tiles/pages.

More in this category