diff --git a/StabilityMatrix.Core/Helper/ImageProcessor.cs b/StabilityMatrix.Core/Helper/ImageProcessor.cs
new file mode 100644
index 00000000..69318237
--- /dev/null
+++ b/StabilityMatrix.Core/Helper/ImageProcessor.cs
@@ -0,0 +1,61 @@
+using SixLabors.ImageSharp;
+using StabilityMatrix.Core.Extensions;
+
+namespace StabilityMatrix.Core.Helper;
+
+public static class ImageProcessor
+{
+ ///
+ /// Get the dimensions of a grid that can hold the given amount of images.
+ ///
+ public static (int rows, int columns) GetGridDimensionsFromImageCount(int count)
+ {
+ if (count <= 1) return (1, 1);
+ if (count == 2) return (1, 2);
+
+ // Prefer one extra row over one extra column,
+ // the row count will be the floor of the square root
+ // and the column count will be floor of count / rows
+ var rows = (int) Math.Floor(Math.Sqrt(count));
+ var columns = (int) Math.Floor((double) count / rows);
+ return (rows, columns);
+ }
+
+ public static Image CreateImageGrid(
+ IReadOnlyList> images,
+ int spacing = 0) where TPixel : unmanaged, IPixel
+ {
+ var (rows, columns) = GetGridDimensionsFromImageCount(images.Count);
+
+ var singleWidth = images[0].Width;
+ var singleHeight = images[0].Height;
+
+ // Make output image
+ var output = new Image(
+ singleWidth * columns + spacing * (columns - 1),
+ singleHeight * rows + spacing * (rows - 1));
+
+
+ // Draw images
+ foreach (var (row, column) in
+ Enumerable.Range(0, rows).Product(Enumerable.Range(0, columns)))
+ {
+ // Stop if we have drawn all images
+ var index = row * columns + column;
+ if (index >= images.Count) break;
+
+ // Get image
+ var image = images[index];
+
+ // Draw image
+ output.Mutate(op =>
+ {
+ op.DrawImage(image,
+ new Point(singleWidth * column + spacing * column,
+ singleHeight * row + spacing * row), 1);
+ });
+ }
+
+ return output;
+ }
+}
diff --git a/StabilityMatrix.Tests/Core/ImageProcessorTests.cs b/StabilityMatrix.Tests/Core/ImageProcessorTests.cs
new file mode 100644
index 00000000..31477115
--- /dev/null
+++ b/StabilityMatrix.Tests/Core/ImageProcessorTests.cs
@@ -0,0 +1,21 @@
+using StabilityMatrix.Core.Helper;
+
+namespace StabilityMatrix.Tests.Core;
+
+[TestClass]
+public class ImageProcessorTests
+{
+ [DataTestMethod]
+ [DataRow(0, 1, 1)]
+ [DataRow(1, 1, 1)]
+ [DataRow(4, 2, 2)]
+ [DataRow(8, 2, 4)]
+ [DataRow(12, 3, 4)]
+ [DataRow(20, 4, 5)]
+ public void TestGetGridDimensionsFromImageCount(int count, int expectedRow, int expectedCols)
+ {
+ var result = ImageProcessor.GetGridDimensionsFromImageCount(count);
+ Assert.AreEqual(expectedRow, result.rows);
+ Assert.AreEqual(expectedCols, result.columns);
+ }
+}