diff --git a/src/ImageSharp/Processing/Delegates/PixelShader.cs b/src/ImageSharp/Processing/Delegates/PixelShader.cs new file mode 100644 index 000000000..fd051c0e6 --- /dev/null +++ b/src/ImageSharp/Processing/Delegates/PixelShader.cs @@ -0,0 +1,12 @@ +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 , , , and fields map the RGBA channels respectively. + public delegate void PixelShader(Span span); +} diff --git a/src/ImageSharp/Processing/Processors/DelegatePixelShaderProcessor.cs b/src/ImageSharp/Processing/Processors/DelegatePixelShaderProcessor.cs new file mode 100644 index 000000000..13ac957ec --- /dev/null +++ b/src/ImageSharp/Processing/Processors/DelegatePixelShaderProcessor.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 +{ + /// + /// Applies a user defined pixel shader effect through a given delegate. + /// + public sealed class DelegatePixelShaderProcessor : IImageProcessor + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The user defined pixel shader to use to modify images. + /// + public DelegatePixelShaderProcessor(PixelShader pixelShader) + { + this.PixelShader = pixelShader; + } + + /// + /// Gets the user defined pixel shader. + /// + public PixelShader PixelShader { get; } + + /// + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + where TPixel : struct, IPixel + { + return new DelegatePixelShaderProcessor(this, source, sourceRectangle); + } + } +} diff --git a/src/ImageSharp/Processing/Processors/DelegatePixelShaderProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/DelegatePixelShaderProcessor{TPixel}.cs new file mode 100644 index 000000000..e6119f2c8 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/DelegatePixelShaderProcessor{TPixel}.cs @@ -0,0 +1,66 @@ +// 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 +{ + /// + /// Performs simple binary threshold filtering against an image. + /// + /// The pixel format. + internal class DelegatePixelShaderProcessor : ImageProcessor + where TPixel : struct, IPixel + { + /// + /// The user defined pixel shader. + /// + private readonly PixelShader 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 DelegatePixelShaderProcessor(DelegatePixelShaderProcessor 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; + PixelShader 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); + + // Run the user defined pixel shader on the current row of pixels + pixelShader(vectorSpan); + + PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, rowSpan); + } + }); + } + } +}