// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Processing.Processors { using System; using System.Collections.Generic; using System.Threading.Tasks; /// /// An to pixelate the colors of an . /// /// The pixel format. public class PixelateProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// /// Initializes a new instance of the class. /// /// The size of the pixels. Must be greater than 0. /// /// is less than 0 or equal to 0. /// public PixelateProcessor(int size) { Guard.MustBeGreaterThan(size, 0, nameof(size)); this.Value = size; } /// /// Gets or the pixel size. /// public int Value { get; } /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int size = this.Value; int offset = this.Value / 2; // 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; } // Get the range on the y-plane to choose from. IEnumerable range = EnumerableExtensions.SteppedRange(minY, i => i < maxY, size); TColor[] target = new TColor[source.Width * source.Height]; using (PixelAccessor sourcePixels = source.Lock()) using (PixelAccessor targetPixels = target.Lock(source.Width, source.Height)) { Parallel.ForEach( range, this.ParallelOptions, y => { int offsetY = y - startY; int offsetPy = offset; for (int x = minX; x < maxX; x += size) { int offsetX = x - startX; int offsetPx = offset; // Make sure that the offset is within the boundary of the image. while (offsetY + offsetPy >= maxY) { offsetPy--; } while (x + offsetPx >= maxX) { offsetPx--; } // Get the pixel color in the centre of the soon to be pixelated area. // ReSharper disable AccessToDisposedClosure TColor pixel = sourcePixels[offsetX + offsetPx, offsetY + offsetPy]; // For each pixel in the pixelate size, set it to the centre color. for (int l = offsetY; l < offsetY + size && l < maxY; l++) { for (int k = offsetX; k < offsetX + size && k < maxX; k++) { targetPixels[k, l] = pixel; } } } }); source.SetPixels(source.Width, source.Height, target); } } } }