static void Main(string[] args) { //ObjectComparison.Do(); //LazyLoading.Do(); //Bugfoot.Do(); ParallelFor.Do(); }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Rectangle sourceRectangle, Configuration configuration) { // Handle resize dimensions identical to the original if (source.Width == destination.Width && source.Height == destination.Height && sourceRectangle == this.CropRectangle) { // the cloned will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); return; } int minY = Math.Max(this.CropRectangle.Y, sourceRectangle.Y); int maxY = Math.Min(this.CropRectangle.Bottom, sourceRectangle.Bottom); int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X); int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right); ParallelFor.WithConfiguration( minY, maxY, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(minX); Span <TPixel> targetRow = destination.GetPixelRowSpan(y - minY); sourceRow.Slice(0, maxX - minX).CopyTo(targetRow); }); }
/// <summary> /// Rotates the image 270 degrees clockwise at the centre point. /// </summary> /// <param name="source">The source image.</param> /// <param name="destination">The destination image.</param> /// <param name="configuration">The configuration.</param> private void Rotate270(ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Configuration configuration) { int width = source.Width; int height = source.Height; Rectangle destinationBounds = destination.Bounds(); ParallelFor.WithConfiguration( 0, height, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); for (int x = 0; x < width; x++) { int newX = height - y - 1; newX = height - newX - 1; int newY = width - x - 1; if (destinationBounds.Contains(newX, newY)) { destination[newX, newY] = sourceRow[x]; } } }); }
public Rgba32 CopyByPixelAccesorSpan() { using (var source = new Image <Rgba32>(1024, 768)) using (var target = new Image <Rgba32>(1024, 768)) { Buffer2D <Rgba32> sourcePixels = source.GetRootFramePixelBuffer(); Buffer2D <Rgba32> targetPixels = target.GetRootFramePixelBuffer(); ParallelFor.WithConfiguration( 0, source.Height, Configuration.Default, y => { Span <Rgba32> sourceRow = sourcePixels.GetRowSpan(y); Span <Rgba32> targetRow = targetPixels.GetRowSpan(y); for (int x = 0; x < source.Width; x++) { targetRow[x] = sourceRow[x]; } }); return(targetPixels[0, 0]); } }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixelDst> source, Rectangle sourceRectangle, Configuration configuration) { Image <TPixelSrc> targetImage = this.Image; PixelBlender <TPixelDst> blender = this.Blender; int locationY = this.Location.Y; // Align start/end positions. Rectangle bounds = targetImage.Bounds(); int minX = Math.Max(this.Location.X, sourceRectangle.X); int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); int targetX = minX - this.Location.X; int minY = Math.Max(this.Location.Y, sourceRectangle.Y); int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); int width = maxX - minX; MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; ParallelFor.WithConfiguration( minY, maxY, configuration, y => { Span <TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width); Span <TPixelSrc> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); blender.Blend <TPixelSrc>(memoryAllocator, background, background, foreground, this.Opacity); }); }
/// <summary> /// Swaps the image at the X-axis, which goes horizontally through the middle at half the height of the image. /// </summary> /// <param name="source">The source image to apply the process to.</param> /// <param name="configuration">The configuration.</param> private void FlipX(ImageFrame <TPixel> source, Configuration configuration) { int height = source.Height; int halfHeight = (int)Math.Ceiling(source.Height * .5F); using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Size())) { ParallelFor.WithConfiguration( 0, halfHeight, configuration, y => { int newY = height - y - 1; Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> altSourceRow = source.GetPixelRowSpan(newY); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); Span <TPixel> altTargetRow = targetPixels.GetRowSpan(newY); sourceRow.CopyTo(altTargetRow); altSourceRow.CopyTo(targetRow); }); Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels); } }
/// <summary> /// Swaps the image at the Y-axis, which goes vertically through the middle at half of the width of the image. /// </summary> /// <param name="source">The source image to apply the process to.</param> /// <param name="configuration">The configuration.</param> private void FlipY(ImageFrame <TPixel> source, Configuration configuration) { int width = source.Width; int height = source.Height; int halfWidth = (int)Math.Ceiling(width * .5F); using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Size())) { ParallelFor.WithConfiguration( 0, height, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = 0; x < halfWidth; x++) { int newX = width - x - 1; targetRow[x] = sourceRow[newX]; targetRow[newX] = sourceRow[x]; } }); Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels); } }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; int endX = interest.Right; Matrix4x4 matrix = this.Matrix; ParallelFor.WithConfiguration( startY, endY, configuration, y => { Span <TPixel> row = source.GetPixelRowSpan(y); for (int x = startX; x < endX; x++) { ref TPixel pixel = ref row[x]; var vector = Vector4.Transform(pixel.ToVector4(), matrix); pixel.PackFromVector4(vector); } }); }
/// <summary> /// Applies the process to the specified portion of the specified <see cref="ImageFrame{TPixel}"/> at the specified location /// and with the specified size. /// </summary> /// <param name="targetPixels">The target pixels to apply the process to.</param> /// <param name="sourcePixels">The source pixels. Cannot be null.</param> /// <param name="sourceRectangle"> /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// </param> /// <param name="kernel">The kernel operator.</param> /// <param name="configuration">The <see cref="Configuration"/></param> private void ApplyConvolution( Buffer2D <TPixel> targetPixels, Buffer2D <TPixel> sourcePixels, Rectangle sourceRectangle, DenseMatrix <float> kernel, Configuration configuration) { int kernelHeight = kernel.Rows; int kernelWidth = kernel.Columns; int radiusY = kernelHeight >> 1; int radiusX = kernelWidth >> 1; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int maxY = endY - 1; int maxX = endX - 1; ParallelFor.WithConfiguration( startY, endY, configuration, y => { Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = startX; x < endX; x++) { Vector4 destination = default; // Apply each matrix multiplier to the color components for each pixel. for (int fy = 0; fy < kernelHeight; fy++) { int fyr = fy - radiusY; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); Span <TPixel> row = sourcePixels.GetRowSpan(offsetY); for (int fx = 0; fx < kernelWidth; fx++) { int fxr = fx - radiusX; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); Vector4 currentColor = row[offsetX].ToVector4().Premultiply(); destination += kernel[fy, fx] * currentColor; } } ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4(destination.UnPremultiply()); } }); }
public static void Explain(this ParallelFor runnable, TextWriter writer) { writer.WriteLine(@" - `CpuBound.Compute` contains a quick sort algorithm - `Parallel.For` is here to divide and conquer compute bound problems faster by applying parallelism - Operations are scheduled on the worker thread pool - Multiple arrays of length 5 to 10 will be sorted in parallel - Parallel.For is a blocking operation "); }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } int width = maxX - minX; using (IMemoryOwner <TPixel> colors = source.MemoryAllocator.Allocate <TPixel>(width)) using (IMemoryOwner <float> amount = source.MemoryAllocator.Allocate <float>(width)) { // Be careful! Do not capture colorSpan & amountSpan in the lambda below! Span <TPixel> colorSpan = colors.GetSpan(); Span <float> amountSpan = amount.GetSpan(); // TODO: Use Span.Fill? for (int i = 0; i < width; i++) { colorSpan[i] = this.Color; amountSpan[i] = this.GraphicsOptions.BlendPercentage; } PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(this.GraphicsOptions); ParallelFor.WithConfiguration( minY, maxY, configuration, y => { Span <TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one blender.Blend(source.MemoryAllocator, destination, colors.GetSpan(), destination, amount.GetSpan()); }); } }
static void Main(string[] args) { DataContractSerialization.Start(null); BinarySerialization.Start(null); XmlSerialization.Start(null); Assemblies.Start(null); Reflect.Start(null); TLS.Start(null); Linq.Start(null); ParallelInvoke.Start(null); ParallelFor.Start(null); ParallelForEach.Start(null); }
/// <summary> /// Executes a parallel For loop. /// </summary> /// <param name="start">Loop start index.</param> /// <param name="stop">Loop stop index.</param> /// <param name="loopBody">Loop body.</param> /// <remarks>The method is used to parallelise for loop by running iterations across /// several threads. /// Example usage: /// <code> /// for ( int i = 0; i < 10; i++ ) /// { /// System.Diagnostics.Debug.WriteLine( "i = " + i ); /// } /// </code> /// can be replaced by: /// <code> /// Parallel.For( 0, 10, delegate( int i ) /// { /// System.Diagnostics.Debug.WriteLine( "i = " + i ); /// } ); /// </code> /// If <c>Parallel.ThreadCount</c> is exactly <c>1</c>, no threads are spawned. /// </remarks> public static void For(int start, int stop, ParallelFor.ForLoopDelegate loopBody) { if (Parallel.threadCount == 1) { for (int i = start; i < stop; i++) { loopBody(i); } } else { lock (lockObject) { ParallelFor parallel = ParallelFor.GetInstance(threadCount); parallel.DoFor(start, stop, loopBody); } } }
/// <summary> /// Get instance of the ParallelFor class for singleton pattern and /// update the number of threads if appropriate. /// </summary> /// <param name="threadCount">The thread count.</param> /// <returns></returns> public static ParallelFor GetInstance(int threadCount) { if (instance == null) { instance = new ParallelFor(); instance.threadCount = threadCount; instance.Initialize(); } else { // Ensure we have the correct number of threads. if (instance.workerThreads.Count != threadCount) { instance.Terminate(); instance.threadCount = threadCount; instance.Initialize(); } } return(instance); }
/// <summary> /// Rotates the image 180 degrees clockwise at the centre point. /// </summary> /// <param name="source">The source image.</param> /// <param name="destination">The destination image.</param> /// <param name="configuration">The configuration.</param> private void Rotate180(ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Configuration configuration) { int width = source.Width; int height = source.Height; ParallelFor.WithConfiguration( 0, height, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> targetRow = destination.GetPixelRowSpan(height - y - 1); for (int x = 0; x < width; x++) { targetRow[width - x - 1] = sourceRow[x]; } }); }
public Rgba32 Copy() { using (var source = new Image <Rgba32>(1024, 768)) using (var target = new Image <Rgba32>(1024, 768)) { ParallelFor.WithConfiguration( 0, source.Height, Configuration.Default, y => { for (int x = 0; x < source.Width; x++) { target[x, y] = source[x, y]; } }); return(target[0, 0]); } }
static void Main(string[] args) { var someData = Enumerable.Range(0, 1000000000).ToList(); StringBuilder sb = new StringBuilder(); sb.Append("for Property " + For.Property(someData) + Environment.NewLine); sb.Append("for Variable " + For.Variable(someData.Count) + Environment.NewLine); sb.Append("parallel For Property " + ParallelFor.Property(someData) + Environment.NewLine); sb.Append("parallel For Variable " + ParallelFor.Variable(someData.Count) + Environment.NewLine); sb.Append("while Variable " + While.Variable(someData.Count) + Environment.NewLine); sb.Append("while Property " + While.Property(someData) + Environment.NewLine); sb.Append("do While Variable " + DoWhile.Variable(someData.Count) + Environment.NewLine); sb.Append("do While Property " + DoWhile.Property(someData) + Environment.NewLine); sb.Append("foreach A " + Foreach.Test(someData) + Environment.NewLine); sb.Append("foreach B " + Foreach.BasicTestOne(someData) + Environment.NewLine); sb.Append("foreach C " + Foreach.BasicTestTwo(someData) + Environment.NewLine); sb.Append("parallel Foreach " + ParallelForEach.Test(someData) + Environment.NewLine); sb.Append("foreach Linq A " + ForeachLinq.Test(someData) + Environment.NewLine); sb.Append("foreach Linq B " + ForeachLinq.BasicForEach(someData) + Environment.NewLine); System.IO.File.WriteAllText(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\loop.txt", sb.ToString()); //set break point in CustomEnumerator method and debug var list = new CustomEnumerator(); foreach (Person item in list) { } Console.ReadLine(); }
public Rgba32 CopySpan() { using (var source = new Image <Rgba32>(1024, 768)) using (var target = new Image <Rgba32>(1024, 768)) { ParallelFor.WithConfiguration( 0, source.Height, Configuration.Default, y => { Span <Rgba32> sourceRow = source.Frames.RootFrame.GetPixelRowSpan(y); Span <Rgba32> targetRow = target.Frames.RootFrame.GetPixelRowSpan(y); for (int x = 0; x < source.Width; x++) { targetRow[x] = sourceRow[x]; } }); return(target[0, 0]); } }
/// <summary> /// Executes a parallel For loop. /// </summary> /// <param name="start">Loop start index.</param> /// <param name="stop">Loop stop index.</param> /// <param name="loopBody">Loop body.</param> /// <param name="cancellationToken">Used to signal if the user wishes to cancel the loop before it completes.</param> /// <remarks>The method is used to parallelise for loop by running iterations across /// several threads. /// Example usage: /// <code> /// for ( int i = 0; i < 10; i++ ) /// { /// System.Diagnostics.Debug.WriteLine( "i = " + i ); /// } /// </code> /// can be replaced by: /// <code> /// Parallel.For( 0, 10, delegate( int i ) /// { /// System.Diagnostics.Debug.WriteLine( "i = " + i ); /// } ); /// </code> /// If <c>Parallel.ThreadCount</c> is exactly <c>1</c>, no threads are spawned. /// </remarks> public static void For(int start, int stop, [NotNull, InstantHandle] Action <int> loopBody, CancellationToken cancellationToken = default(CancellationToken)) { if (loopBody == null) { throw new ArgumentNullException("loopBody"); } if (Parallel.threadCount == 1) { for (int i = start; i < stop; i++) { loopBody(i); cancellationToken.ThrowIfCancellationRequested(); } } else { lock (lockObject) { ParallelFor parallel = ParallelFor.GetInstance(threadCount); parallel.DoFor(start, stop, loopBody, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } } }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { float threshold = this.Threshold * 255F; TPixel upper = this.UpperColor; TPixel lower = this.LowerColor; var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; int endX = interest.Right; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); ParallelFor.WithConfiguration( startY, endY, configuration, y => { Span <TPixel> row = source.GetPixelRowSpan(y); Rgba32 rgba = default; for (int x = startX; x < endX; x++) { ref TPixel color = ref row[x]; color.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); color = luminance >= threshold ? upper : lower; } }); }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); int width = maxX - minX; // If there's no reason for blending, then avoid it. if (this.IsSolidBrushWithoutBlending(out SolidBrush <TPixel> solidBrush)) { ParallelFor.WithConfiguration( minY, maxY, configuration, y => { source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); }); } else { // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } using (IMemoryOwner <float> amount = source.MemoryAllocator.Allocate <float>(width)) using (BrushApplicator <TPixel> applicator = this.brush.CreateApplicator( source, sourceRectangle, this.options)) { amount.GetSpan().Fill(1f); ParallelFor.WithConfiguration( minY, maxY, configuration, y => { int offsetY = y - startY; int offsetX = minX - startX; applicator.Apply(amount.GetSpan(), offsetX, offsetY); }); } } }
/// <inheritdoc/> protected override void OnFrameApply( ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; TPixel glowColor = this.GlowColor; Vector2 centre = Rectangle.Center(sourceRectangle); float maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } int width = maxX - minX; using (IMemoryOwner <TPixel> rowColors = Configuration.Default.MemoryAllocator.Allocate <TPixel>(width)) { Buffer2D <TPixel> sourcePixels = source.PixelBuffer; rowColors.GetSpan().Fill(glowColor); ParallelFor.WithConfiguration( minY, maxY, configuration, y => { int offsetY = y - startY; for (int x = minX; x < maxX; x++) { int offsetX = x - startX; float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); TPixel packed = default(TPixel); packed.PackFromVector4( PremultipliedLerp( sourceColor, glowColor.ToVector4(), 1 - (.95F * (distance / maxDistance)))); sourcePixels[offsetX, offsetY] = packed; } }); } }
/// <inheritdoc /> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { DenseMatrix <float>[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast }; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // we need a clean copy for each pass to start from using (ImageFrame <TPixel> cleanCopy = source.Clone()) { new ConvolutionProcessor <TPixel>(kernels[0]).Apply(source, sourceRectangle, configuration); if (kernels.Length == 1) { return; } int shiftY = startY; int shiftX = startX; // Reset offset if necessary. if (minX > 0) { shiftX = 0; } if (minY > 0) { shiftY = 0; } // Additional runs. // ReSharper disable once ForCanBeConvertedToForeach for (int i = 1; i < kernels.Length; i++) { using (ImageFrame <TPixel> pass = cleanCopy.Clone()) { new ConvolutionProcessor <TPixel>(kernels[i]).Apply(pass, sourceRectangle, configuration); Buffer2D <TPixel> passPixels = pass.PixelBuffer; Buffer2D <TPixel> targetPixels = source.PixelBuffer; ParallelFor.WithConfiguration( minY, maxY, configuration, y => { int offsetY = y - shiftY; ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(passPixels.GetRowSpan(offsetY)); ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(targetPixels.GetRowSpan(offsetY)); for (int x = minX; x < maxX; x++) { int offsetX = x - shiftX; // Grab the max components of the two pixels ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX); ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX); var pixelValue = Vector4.Max( currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); currentTargetPixel.PackFromVector4(pixelValue); } });
/// <inheritdoc/> protected override void OnFrameApply( ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Rectangle sourceRectangle, Configuration configuration) { int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; Rectangle sourceBounds = source.Bounds(); var targetBounds = new Rectangle(0, 0, width, height); // Since could potentially be resizing the canvas we might need to re-calculate the matrix Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); // Convert from screen to world space. Matrix3x2.Invert(matrix, out matrix); if (this.Sampler is NearestNeighborResampler) { ParallelFor.WithConfiguration( 0, height, configuration, y => { Span <TPixel> destRow = destination.GetPixelRowSpan(y); for (int x = 0; x < width; x++) { var point = Point.Transform(new Point(x, y), matrix); if (sourceBounds.Contains(point.X, point.Y)) { destRow[x] = source[point.X, point.Y]; } } }); return; } int maxSourceX = source.Width - 1; int maxSourceY = source.Height - 1; (float radius, float scale, float ratio)xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); (float radius, float scale, float ratio)yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); float xScale = xRadiusScale.scale; float yScale = yRadiusScale.scale; var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); IResampler sampler = this.Sampler; var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); MemoryAllocator memoryAllocator = configuration.MemoryAllocator; using (Buffer2D <float> yBuffer = memoryAllocator.Allocate2D <float>(yLength, height)) using (Buffer2D <float> xBuffer = memoryAllocator.Allocate2D <float>(xLength, height)) { ParallelFor.WithConfiguration( 0, height, configuration, y => { ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y));
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width) { throw new ArgumentOutOfRangeException(nameof(this.BrushSize)); } int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int maxY = endY - 1; int maxX = endX - 1; int radius = this.BrushSize >> 1; int levels = this.Levels; using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Size())) { source.CopyTo(targetPixels); ParallelFor.WithConfiguration( startY, maxY, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = startX; x < endX; x++) { int maxIntensity = 0; int maxIndex = 0; int[] intensityBin = new int[levels]; float[] redBin = new float[levels]; float[] blueBin = new float[levels]; float[] greenBin = new float[levels]; for (int fy = 0; fy <= radius; fy++) { int fyr = fy - radius; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); for (int fx = 0; fx <= radius; fx++) { int fxr = fx - radius; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); var vector = sourceOffsetRow[offsetX].ToVector4(); float sourceRed = vector.X; float sourceBlue = vector.Z; float sourceGreen = vector.Y; int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); intensityBin[currentIntensity]++; blueBin[currentIntensity] += sourceBlue; greenBin[currentIntensity] += sourceGreen; redBin[currentIntensity] += sourceRed; if (intensityBin[currentIntensity] > maxIntensity) { maxIntensity = intensityBin[currentIntensity]; maxIndex = currentIntensity; } } float red = MathF.Abs(redBin[maxIndex] / maxIntensity); float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); } } }); Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels); } }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; TPixel glowColor = this.GlowColor; Vector2 center = Rectangle.Center(sourceRectangle); float finalRadius = this.Radius.Calculate(source.Size()); float maxDistance = finalRadius > 0 ? MathF.Min(finalRadius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } int width = maxX - minX; using (IMemoryOwner <TPixel> rowColors = source.MemoryAllocator.Allocate <TPixel>(width)) { // Be careful! Do not capture rowColorsSpan in the lambda below! Span <TPixel> rowColorsSpan = rowColors.GetSpan(); for (int i = 0; i < width; i++) { rowColorsSpan[i] = glowColor; } ParallelFor.WithTemporaryBuffer <float>( minY, maxY, configuration, width, (y, amounts) => { Span <float> amountsSpan = amounts.GetSpan(); int offsetY = y - startY; int offsetX = minX - startX; for (int i = 0; i < width; i++) { float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY)); amountsSpan[i] = (this.GraphicsOptions.BlendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1); } Span <TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan); }); } }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int kernelLength = this.KernelXY.Rows; int radius = kernelLength >> 1; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int maxY = endY - 1; int maxX = endX - 1; using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Size())) { source.CopyTo(targetPixels); ParallelFor.WithConfiguration( startY, endY, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = startX; x < endX; x++) { float red = 0; float green = 0; float blue = 0; // Apply each matrix multiplier to the color components for each pixel. for (int fy = 0; fy < kernelLength; fy++) { int fyr = fy - radius; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); for (int fx = 0; fx < kernelLength; fx++) { int fxr = fx - radius; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); currentColor *= this.KernelXY[fy, fx]; red += currentColor.X; green += currentColor.Y; blue += currentColor.Z; } } ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); } }); Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels); } }
public Worker(ParallelFor p, byte index) { this.source = p; this.threadIndex = index; }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int kernelYHeight = this.KernelY.Rows; int kernelYWidth = this.KernelY.Columns; int kernelXHeight = this.KernelX.Rows; int kernelXWidth = this.KernelX.Columns; int radiusY = kernelYHeight >> 1; int radiusX = kernelXWidth >> 1; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int maxY = endY - 1; int maxX = endX - 1; using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Width, source.Height)) { source.CopyTo(targetPixels); ParallelFor.WithConfiguration( startY, endY, configuration, y => { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = startX; x < endX; x++) { float rX = 0; float gX = 0; float bX = 0; float rY = 0; float gY = 0; float bY = 0; // Apply each matrix multiplier to the color components for each pixel. for (int fy = 0; fy < kernelYHeight; fy++) { int fyr = fy - radiusY; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); for (int fx = 0; fx < kernelXWidth; fx++) { int fxr = fx - radiusX; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); if (fy < kernelXHeight) { Vector4 kx = this.KernelX[fy, fx] * currentColor; rX += kx.X; gX += kx.Y; bX += kx.Z; } if (fx < kernelYWidth) { Vector4 ky = this.KernelY[fy, fx] * currentColor; rY += ky.X; gY += ky.Y; bY += ky.Z; } } } float red = MathF.Sqrt((rX * rX) + (rY * rY)); float green = MathF.Sqrt((gX * gX) + (gY * gY)); float blue = MathF.Sqrt((bX * bX) + (bY * bY)); ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); } }); Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels); } }