diff --git a/src/ImageSharp/Processing/Delegates/PositionAwarePixelShader.cs b/src/ImageSharp/Processing/Delegates/PositionAwarePixelShader.cs
new file mode 100644
index 000000000..08314600a
--- /dev/null
+++ b/src/ImageSharp/Processing/Delegates/PositionAwarePixelShader.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Numerics;
+
+namespace SixLabors.ImageSharp.Processing.Delegates
+{
+ ///
+ /// A representing a user defined pixel shader.
+ ///
+ /// The target row of pixels to process.
+ /// The initial vertical offset for the input pixels to process.
+ /// The initial horizontal offset for the input pixels to process.
+ /// The , , , and fields map the RGBA channels respectively.
+ public delegate void PositionAwarePixelShader(Span span, int offsetY, int offsetX);
+}
diff --git a/src/ImageSharp/Processing/Processors/PixelShading/DelegatePixelShaderProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/PixelShading/DelegatePixelShaderProcessor{TPixel}.cs
index c773e8b80..d15614cc4 100644
--- a/src/ImageSharp/Processing/Processors/PixelShading/DelegatePixelShaderProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/PixelShading/DelegatePixelShaderProcessor{TPixel}.cs
@@ -13,7 +13,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.PixelShading
{
///
- /// Performs simple binary threshold filtering against an image.
+ /// Applies a user defined pixel shader effect through a given delegate.
///
/// The pixel format.
internal class DelegatePixelShaderProcessor : ImageProcessor
diff --git a/src/ImageSharp/Processing/Processors/PixelShading/PositionAwarePixelShaderProcessor.cs b/src/ImageSharp/Processing/Processors/PixelShading/PositionAwarePixelShaderProcessor.cs
new file mode 100644
index 000000000..60125b2e2
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/PixelShading/PositionAwarePixelShaderProcessor.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Delegates;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Processors.PixelShading
+{
+ ///
+ /// Applies a user defined pixel shader effect through a given delegate.
+ ///
+ public sealed class PositionAwarePixelShaderProcessor : IImageProcessor
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The user defined pixel shader to use to modify images.
+ ///
+ public PositionAwarePixelShaderProcessor(PositionAwarePixelShader pixelShader)
+ {
+ this.PixelShader = pixelShader;
+ }
+
+ ///
+ /// Gets the user defined pixel shader.
+ ///
+ public PositionAwarePixelShader PixelShader { get; }
+
+ ///
+ public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle)
+ where TPixel : struct, IPixel
+ {
+ return new PositionAwarePixelShader(this, source, sourceRectangle);
+ }
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/PixelShading/PositionAwarePixelShaderProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/PixelShading/PositionAwarePixelShaderProcessor{TPixel}.cs
new file mode 100644
index 000000000..55ad325ad
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/PixelShading/PositionAwarePixelShaderProcessor{TPixel}.cs
@@ -0,0 +1,65 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Delegates;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Processors.PixelShading
+{
+ ///
+ /// Applies a user defined pixel shader effect through a given delegate.
+ ///
+ /// The pixel format.
+ internal class PositionAwarePixelShaderProcessor : ImageProcessor
+ where TPixel : struct, IPixel
+ {
+ ///
+ /// The user defined pixel shader.
+ ///
+ private readonly PositionAwarePixelShader pixelShader;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The defining the processor parameters.
+ /// The source for the current processor instance.
+ /// The source area to process for the current processor instance.
+ public PositionAwarePixelShaderProcessor(PositionAwarePixelShaderProcessor definition, Image source, Rectangle sourceRectangle)
+ : base(source, sourceRectangle)
+ {
+ this.pixelShader = definition.PixelShader;
+ }
+
+ ///
+ protected override void OnFrameApply(ImageFrame source)
+ {
+ var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
+ int startX = interest.X;
+ PositionAwarePixelShader pixelShader = this.pixelShader;
+
+ ParallelHelper.IterateRowsWithTempBuffer(
+ interest,
+ this.Configuration,
+ (rows, vectorBuffer) =>
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span vectorSpan = vectorBuffer.Span;
+ int length = vectorSpan.Length;
+ Span rowSpan = source.GetPixelRowSpan(y).Slice(startX, length);
+ PixelOperations.Instance.ToVector4(this.Configuration, rowSpan, vectorSpan);
+
+ pixelShader(vectorSpan, y, startX);
+
+ PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, rowSpan);
+ }
+ });
+ }
+ }
+}