diff --git a/src/ImageSharp/Processing/Extensions/Transforms/SwizzleExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/SwizzleExtensions.cs
new file mode 100644
index 0000000000..c02b3a00d6
--- /dev/null
+++ b/src/ImageSharp/Processing/Extensions/Transforms/SwizzleExtensions.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Processing.Processors.Transforms;
+
+namespace SixLabors.ImageSharp.Processing.Extensions.Transforms
+{
+ ///
+ /// Defines extensions that allow the application of swizzle operations on an
+ ///
+ public static class SwizzleExtensions
+ {
+ ///
+ /// Swizzles an image.
+ ///
+ /// The image to swizzle.
+ /// The swizzler function.
+ /// The swizzler function type.
+ /// The to allow chaining of operations.
+ public static IImageProcessingContext Swizzle(this IImageProcessingContext source, TSwizzler swizzler)
+ where TSwizzler : struct, ISwizzler
+ => source.ApplyProcessor(new SwizzleProcessor(swizzler));
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ISwizzler.cs b/src/ImageSharp/Processing/Processors/Transforms/ISwizzler.cs
new file mode 100644
index 0000000000..efa3e35a4b
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Transforms/ISwizzler.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Processing.Processors.Transforms
+{
+ ///
+ /// Encapsulate an algorithm to swizzle pixels in an image.
+ ///
+ public interface ISwizzler
+ {
+ ///
+ /// Gets the size of the image after transformation.
+ ///
+ Size DestinationSize { get; }
+
+ ///
+ /// Applies the swizzle transformation to a given point.
+ ///
+ /// Point to transform.
+ /// The transformed point.
+ Point Transform(Point point);
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler,TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler,TPixel}.cs
new file mode 100644
index 0000000000..aab17d2920
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler,TPixel}.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Transforms
+{
+ internal class SwizzleProcessor : TransformProcessor
+ where TSwizzler : struct, ISwizzler
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly TSwizzler swizzler;
+ private readonly Size destinationSize;
+
+ public SwizzleProcessor(Configuration configuration, TSwizzler swizzler, Image source, Rectangle sourceRectangle)
+ : base(configuration, source, sourceRectangle)
+ {
+ this.swizzler = swizzler;
+ this.destinationSize = swizzler.DestinationSize;
+ }
+
+ protected override Size GetDestinationSize()
+ => this.destinationSize;
+
+ protected override void OnFrameApply(ImageFrame source, ImageFrame destination)
+ {
+ Point p = default;
+ Point newPoint;
+ for (p.Y = 0; p.Y < source.Height; p.Y++)
+ {
+ Span rowSpan = source.GetPixelRowSpan(p.Y);
+ for (p.X = 0; p.X < source.Width; p.X++)
+ {
+ newPoint = this.swizzler.Transform(p);
+ destination[newPoint.X, newPoint.Y] = rowSpan[p.X];
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler}.cs b/src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler}.cs
new file mode 100644
index 0000000000..d48257334d
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler}.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Transforms
+{
+ ///
+ /// Defines a swizzle operation on an image.
+ ///
+ /// The swizzle function type.
+ public sealed class SwizzleProcessor : IImageProcessor
+ where TSwizzler : struct, ISwizzler
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The swizzler operation.
+ public SwizzleProcessor(TSwizzler swizzler)
+ {
+ this.Swizzler = swizzler;
+ }
+
+ ///
+ /// Gets the swizzler operation.
+ ///
+ public TSwizzler Swizzler { get; }
+
+ ///
+ public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle)
+ where TPixel : unmanaged, IPixel
+ => new SwizzleProcessor(configuration, this.Swizzler, source, sourceRectangle);
+ }
+}
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SwizzleTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SwizzleTests.cs
new file mode 100644
index 0000000000..f508744fae
--- /dev/null
+++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SwizzleTests.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Processing.Extensions.Transforms;
+using SixLabors.ImageSharp.Processing.Processors.Transforms;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
+{
+ [GroupOutput("Transforms")]
+ public class SwizzleTests
+ {
+ private struct InvertXAndYSwizzler : ISwizzler
+ {
+ public InvertXAndYSwizzler(Size sourceSize)
+ {
+ this.DestinationSize = new Size(sourceSize.Height, sourceSize.Width);
+ }
+
+ public Size DestinationSize { get; }
+
+ public Point Transform(Point point)
+ => new Point(point.Y, point.X);
+ }
+
+ [Theory]
+ [WithTestPatternImages(20, 37, PixelTypes.Rgba32)]
+ [WithTestPatternImages(53, 37, PixelTypes.Byte4)]
+ [WithTestPatternImages(17, 32, PixelTypes.Rgba32)]
+ public void InvertXAndYSwizzle(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image expectedImage = provider.GetImage();
+ using Image image = provider.GetImage();
+
+ image.Mutate(ctx => ctx.Swizzle(new InvertXAndYSwizzler(new Size(image.Width, image.Height))));
+
+ image.DebugSave(
+ provider,
+ nameof(InvertXAndYSwizzler),
+ appendPixelTypeToFileName: false,
+ appendSourceFileOrDescription: true);
+
+ image.Mutate(ctx => ctx.Swizzle(new InvertXAndYSwizzler(new Size(image.Width, image.Height))));
+
+ image.DebugSave(
+ provider,
+ "Unswizzle",
+ appendPixelTypeToFileName: false,
+ appendSourceFileOrDescription: true);
+
+ ImageComparer.Exact.VerifySimilarity(expectedImage, image);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/SwizzleTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/SwizzleTests.cs
new file mode 100644
index 0000000000..cde6aeca36
--- /dev/null
+++ b/tests/ImageSharp.Tests/Processing/Transforms/SwizzleTests.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Processing.Extensions.Transforms;
+using SixLabors.ImageSharp.Processing.Processors.Transforms;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Processing.Transforms
+{
+ public class SwizzleTests : BaseImageOperationsExtensionTest
+ {
+ private struct InvertXAndYSwizzler : ISwizzler
+ {
+ public InvertXAndYSwizzler(Size sourceSize)
+ {
+ this.DestinationSize = new Size(sourceSize.Height, sourceSize.Width);
+ }
+
+ public Size DestinationSize { get; }
+
+ public Point Transform(Point point)
+ => new Point(point.Y, point.X);
+ }
+
+ [Fact]
+ public void InvertXAndYSwizzlerSetsCorrectSizes()
+ {
+ int width = 5;
+ int height = 10;
+
+ this.operations.Swizzle(new InvertXAndYSwizzler(new Size(width, height)));
+ SwizzleProcessor processor = this.Verify>();
+
+ Assert.Equal(processor.Swizzler.DestinationSize.Width, height);
+ Assert.Equal(processor.Swizzler.DestinationSize.Height, width);
+
+ this.operations.Swizzle(new InvertXAndYSwizzler(processor.Swizzler.DestinationSize));
+ SwizzleProcessor processor2 = this.Verify>(1);
+
+ Assert.Equal(processor2.Swizzler.DestinationSize.Width, width);
+ Assert.Equal(processor2.Swizzler.DestinationSize.Height, height);
+ }
+ }
+}