// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Processing.Processors { using System; using System.Numerics; using System.Threading.Tasks; /// /// Provides methods that allow the skewing of images. /// /// The pixel format. public class SkewProcessor : Matrix3x2Processor where TColor : struct, IPackedPixel, IEquatable { /// /// The transform matrix to apply. /// private Matrix3x2 processMatrix; /// /// Gets or sets the angle of rotation along the x-axis in degrees. /// public float AngleX { get; set; } /// /// Gets or sets the angle of rotation along the y-axis in degrees. /// public float AngleY { get; set; } /// /// Gets or sets a value indicating whether to expand the canvas to fit the skewed image. /// public bool Expand { get; set; } = true; /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { int height = this.CanvasRectangle.Height; int width = this.CanvasRectangle.Width; Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix); TColor[] target = PixelPool.RentPixels(width * height); using (PixelAccessor sourcePixels = source.Lock()) using (PixelAccessor targetPixels = target.Lock(width, height)) { Parallel.For( 0, height, this.ParallelOptions, y => { for (int x = 0; x < width; x++) { Point transformedPoint = Point.Skew(new Point(x, y), matrix); if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y)) { targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y]; } } }); } source.SetPixels(width, height, target); } /// protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) { this.processMatrix = Point.CreateSkew(new Point(0, 0), -this.AngleX, -this.AngleY); if (this.Expand) { this.CreateNewCanvas(sourceRectangle, this.processMatrix); } } } }