📷 A modern, cross-platform, 2D Graphics library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

194 lines
6.8 KiB

// <copyright file="RotateFlip.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Samplers
{
using System;
using System.Threading.Tasks;
/// <summary>
/// Provides methods that allow the rotation and flipping of an image around its center point.
/// </summary>
public class RotateFlip : ParallelImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="RotateFlip"/> class.
/// </summary>
/// <param name="rotateType">The <see cref="RotateType"/> used to perform rotation.</param>
/// <param name="flipType">The <see cref="FlipType"/> used to perform flipping.</param>
public RotateFlip(RotateType rotateType, FlipType flipType)
{
this.RotateType = rotateType;
this.FlipType = flipType;
}
/// <summary>
/// Gets the <see cref="FlipType"/> used to perform flipping.
/// </summary>
public FlipType FlipType { get; }
/// <summary>
/// Gets the <see cref="RotateType"/> used to perform rotation.
/// </summary>
public RotateType RotateType { get; }
/// <inheritdoc/>
public override int Parallelism { get; set; } = 1;
/// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
switch (this.RotateType)
{
case RotateType.Rotate90:
Rotate90(target, source);
break;
case RotateType.Rotate180:
Rotate180(target, source);
break;
case RotateType.Rotate270:
Rotate270(target, source);
break;
default:
target.ClonePixels(target.Width, target.Height, source.Pixels);
break;
}
switch (this.FlipType)
{
// No default needed as we have already set the pixels.
case FlipType.Vertical:
FlipX(target);
break;
case FlipType.Horizontal:
FlipY(target);
break;
}
}
/// <summary>
/// Rotates the image 270 degrees clockwise at the centre point.
/// </summary>
/// <param name="target">The target image.</param>
/// <param name="source">The source image.</param>
private static void Rotate270(ImageBase target, ImageBase source)
{
int width = source.Width;
int height = source.Height;
Image temp = new Image(height, width);
Parallel.For(0, height,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = height - y - 1;
newX = height - newX - 1;
int newY = width - x - 1;
newY = width - newY - 1;
temp[newX, newY] = source[x, y];
}
});
target.SetPixels(height, width, temp.Pixels);
}
/// <summary>
/// Rotates the image 180 degrees clockwise at the centre point.
/// </summary>
/// <param name="target">The target image.</param>
/// <param name="source">The source image.</param>
private static void Rotate180(ImageBase target, ImageBase source)
{
int width = source.Width;
int height = source.Height;
Parallel.For(0, height,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = width - x - 1;
int newY = height - y - 1;
target[newX, newY] = source[x, y];
}
});
}
/// <summary>
/// Rotates the image 90 degrees clockwise at the centre point.
/// </summary>
/// <param name="target">The target image.</param>
/// <param name="source">The source image.</param>
private static void Rotate90(ImageBase target, ImageBase source)
{
int width = source.Width;
int height = source.Height;
Image temp = new Image(height, width);
Parallel.For(0, height,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = height - y - 1;
temp[newX, x] = source[x, y];
}
});
target.SetPixels(height, width, temp.Pixels);
}
/// <summary>
/// Swaps the image at the X-axis, which goes horizontally through the middle
/// at half the height of the image.
/// </summary>
/// <param name="target">Target image to apply the process to.</param>
private static void FlipX(ImageBase target)
{
int width = target.Width;
int height = target.Height;
int halfHeight = (int)Math.Ceiling(target.Height * .5);
ImageBase temp = new Image(width, height);
temp.ClonePixels(width, height, target.Pixels);
Parallel.For(0, halfHeight,
y =>
{
for (int x = 0; x < width; x++)
{
int newY = height - y - 1;
target[x, y] = temp[x, newY];
target[x, newY] = temp[x, y];
}
});
}
/// <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="target">Target image to apply the process to.</param>
private static void FlipY(ImageBase target)
{
int width = target.Width;
int height = target.Height;
int halfWidth = (int)Math.Ceiling(width / 2d);
ImageBase temp = new Image(width, height);
temp.ClonePixels(width, height, target.Pixels);
Parallel.For(0, height,
y =>
{
for (int x = 0; x < halfWidth; x++)
{
int newX = width - x - 1;
target[x, y] = temp[newX, y];
target[newX, y] = temp[x, y];
}
});
}
}
}