Browse Source

Moved the Flip and Rotate code from FlipRotate to their own Processors and call those inside RotateFlip.

Former-commit-id: 59a0db810427fcfd9c7426392f5de94317d928bd
Former-commit-id: 89d27c015fbc972372f3697c06864dd71f458574
Former-commit-id: 160b946dcbfc868be3d014c2ef6410cbb40d4ef7
af/merge-core
dirk 10 years ago
parent
commit
3a2d001eaf
  1. 41
      src/ImageProcessorCore/Samplers/Flip.cs
  2. 6
      src/ImageProcessorCore/Samplers/Options/RotateType.cs
  3. 119
      src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs
  4. 240
      src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs
  5. 139
      src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs
  6. 16
      src/ImageProcessorCore/Samplers/Rotate.cs
  7. 15
      src/ImageProcessorCore/Samplers/RotateFlip.cs

41
src/ImageProcessorCore/Samplers/Flip.cs

@ -0,0 +1,41 @@
// <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 ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Flips an image by the given instructions.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/></returns>
public static Image<T, TP> Flip<T, TP>(this Image<T, TP> source, FlipType flipType, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
FlipProcessor<T, TP> processor = new FlipProcessor<T, TP>(flipType);
processor.OnProgress += progressHandler;
try
{
return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
}
}

6
src/ImageProcessorCore/Samplers/Options/RotateType.cs

@ -18,16 +18,16 @@ namespace ImageProcessorCore
/// <summary> /// <summary>
/// Rotate the image by 90 degrees clockwise. /// Rotate the image by 90 degrees clockwise.
/// </summary> /// </summary>
Rotate90, Rotate90 = 90,
/// <summary> /// <summary>
/// Rotate the image by 180 degrees clockwise. /// Rotate the image by 180 degrees clockwise.
/// </summary> /// </summary>
Rotate180, Rotate180 = 180,
/// <summary> /// <summary>
/// Rotate the image by 270 degrees clockwise. /// Rotate the image by 270 degrees clockwise.
/// </summary> /// </summary>
Rotate270 Rotate270 = 270
} }
} }

119
src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs

@ -0,0 +1,119 @@
// <copyright file="RotateFlipProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System;
using System.Threading.Tasks;
/// <summary>
/// Provides methods that allow the flipping of an image around its center point.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class FlipProcessor<T, TP> : ImageSampler<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="FlipProcessor{T,TP}"/> class.
/// </summary>
/// <param name="flipType">The <see cref="FlipType"/> used to perform flipping.</param>
public FlipProcessor(FlipType flipType)
{
this.FlipType = flipType;
}
/// <summary>
/// Gets the <see cref="FlipType"/> used to perform flipping.
/// </summary>
public FlipType FlipType { get; }
/// <inheritdoc/>
protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
target.ClonePixels(target.Width, target.Height, source.Pixels);
switch (this.FlipType)
{
// No default needed as we have already set the pixels.
case FlipType.Vertical:
this.FlipX(target);
break;
case FlipType.Horizontal:
this.FlipY(target);
break;
}
}
/// <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 void FlipX(ImageBase<T, TP> target)
{
int width = target.Width;
int height = target.Height;
int halfHeight = (int)Math.Ceiling(target.Height * .5F);
Image<T, TP> temp = new Image<T, TP>(width, height);
temp.ClonePixels(width, height, target.Pixels);
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
halfHeight,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
{
int newY = height - y - 1;
targetPixels[x, y] = tempPixels[x, newY];
targetPixels[x, newY] = tempPixels[x, y];
}
this.OnRowProcessed();
});
}
}
/// <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 void FlipY(ImageBase<T, TP> target)
{
int width = target.Width;
int height = target.Height;
int halfWidth = (int)Math.Ceiling(width * .5F);
Image<T, TP> temp = new Image<T, TP>(width, height);
temp.ClonePixels(width, height, target.Pixels);
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < halfWidth; x++)
{
int newX = width - x - 1;
targetPixels[x, y] = tempPixels[newX, y];
targetPixels[newX, y] = tempPixels[x, y];
}
this.OnRowProcessed();
});
}
}
}
}

240
src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs

@ -1,240 +0,0 @@
// <copyright file="RotateFlipProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System;
using System.Threading.Tasks;
/// <summary>
/// Provides methods that allow the rotation and flipping of an image around its center point.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class RotateFlipProcessor<T, TP> : ImageSampler<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="RotateFlipProcessor{T,TP}"/> 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 RotateFlipProcessor(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/>
protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
switch (this.RotateType)
{
case RotateType.Rotate90:
this.Rotate90(target, source);
break;
case RotateType.Rotate180:
this.Rotate180(target, source);
break;
case RotateType.Rotate270:
this.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:
this.FlipX(target);
break;
case FlipType.Horizontal:
this.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 void Rotate270(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
int width = source.Width;
int height = source.Height;
Image<T, TP> temp = new Image<T, TP>(height, width);
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
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;
tempPixels[newX, newY] = sourcePixels[x, y];
}
this.OnRowProcessed();
});
}
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 void Rotate180(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
int width = source.Width;
int height = source.Height;
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = width - x - 1;
int newY = height - y - 1;
targetPixels[newX, newY] = sourcePixels[x, y];
}
this.OnRowProcessed();
});
}
}
/// <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 void Rotate90(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
int width = source.Width;
int height = source.Height;
Image<T, TP> temp = new Image<T, TP>(height, width);
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = height - y - 1;
tempPixels[newX, x] = sourcePixels[x, y];
}
this.OnRowProcessed();
});
}
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 void FlipX(ImageBase<T, TP> target)
{
int width = target.Width;
int height = target.Height;
int halfHeight = (int)Math.Ceiling(target.Height * .5F);
Image<T, TP> temp = new Image<T, TP>(width, height);
temp.ClonePixels(width, height, target.Pixels);
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
halfHeight,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
{
int newY = height - y - 1;
targetPixels[x, y] = tempPixels[x, newY];
targetPixels[x, newY] = tempPixels[x, y];
}
this.OnRowProcessed();
});
}
}
/// <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 void FlipY(ImageBase<T, TP> target)
{
int width = target.Width;
int height = target.Height;
int halfWidth = (int)Math.Ceiling(width * .5F);
Image<T, TP> temp = new Image<T, TP>(width, height);
temp.ClonePixels(width, height, target.Pixels);
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < halfWidth; x++)
{
int newX = width - x - 1;
targetPixels[x, y] = tempPixels[newX, y];
targetPixels[newX, y] = tempPixels[x, y];
}
this.OnRowProcessed();
});
}
}
}
}

139
src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs

@ -34,6 +34,11 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void OnApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
if (Angle == 90 || Angle == 180 || Angle == 270)
{
return;
}
this.processMatrix = Point.CreateRotation(new Point(0, 0), -this.Angle); this.processMatrix = Point.CreateRotation(new Point(0, 0), -this.Angle);
if (this.Expand) if (this.Expand)
{ {
@ -44,6 +49,11 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{ {
if (OptimizedApply(target, source))
{
return;
}
int height = target.Height; int height = target.Height;
int width = target.Width; int width = target.Width;
Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix); Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix);
@ -70,5 +80,134 @@ namespace ImageProcessorCore.Processors
}); });
} }
} }
/// <summary>
/// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees.
/// </summary>
/// <param name="target">The target image.</param>
/// <param name="source">The source image.</param>
/// <returns></returns>
private bool OptimizedApply(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
if (Angle == 90)
{
this.Rotate90(target, source);
return true;
}
if (Angle == 180)
{
this.Rotate180(target, source);
return true;
}
if (Angle == 270)
{
this.Rotate270(target, source);
return true;
}
return false;
}
/// <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 void Rotate270(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
int width = source.Width;
int height = source.Height;
Image<T, TP> temp = new Image<T, TP>(height, width);
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
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;
tempPixels[newX, newY] = sourcePixels[x, y];
}
this.OnRowProcessed();
});
}
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 void Rotate180(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
int width = source.Width;
int height = source.Height;
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = width - x - 1;
int newY = height - y - 1;
targetPixels[newX, newY] = sourcePixels[x, y];
}
this.OnRowProcessed();
});
}
}
/// <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 void Rotate90(ImageBase<T, TP> target, ImageBase<T, TP> source)
{
int width = source.Width;
int height = source.Height;
Image<T, TP> temp = new Image<T, TP>(height, width);
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> tempPixels = temp.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
{
int newX = height - y - 1;
tempPixels[newX, x] = sourcePixels[x, y];
}
this.OnRowProcessed();
});
}
target.SetPixels(height, width, temp.Pixels);
}
} }
} }

16
src/ImageProcessorCore/Samplers/Rotate.cs

@ -28,6 +28,22 @@ namespace ImageProcessorCore
return Rotate(source, degrees, true, progressHandler); return Rotate(source, degrees, true, progressHandler);
} }
/// <summary>
/// Rotates and flips an image by the given instructions.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image to rotate.</param>
/// <param name="rotateType">The <see cref="RotateType"/> to perform the rotation.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/></returns>
public static Image<T, TP> Rotate<T, TP>(this Image<T, TP> source, RotateType rotateType, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return Rotate(source, (float)rotateType, false, progressHandler);
}
/// <summary> /// <summary>
/// Rotates an image by the given angle in degrees. /// Rotates an image by the given angle in degrees.
/// </summary> /// </summary>

15
src/ImageProcessorCore/Samplers/RotateFlip.cs

@ -18,7 +18,6 @@ namespace ImageProcessorCore
/// <typeparam name="T">The pixel format.</typeparam> /// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam> /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image to rotate, flip, or both.</param> /// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="rotateType">The <see cref="RotateType"/> to perform the rotation.</param>
/// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param> /// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param> /// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/></returns> /// <returns>The <see cref="Image"/></returns>
@ -26,17 +25,9 @@ namespace ImageProcessorCore
where T : IPackedVector<TP> where T : IPackedVector<TP>
where TP : struct where TP : struct
{ {
RotateFlipProcessor<T, TP> processor = new RotateFlipProcessor<T, TP>(rotateType, flipType); return source
processor.OnProgress += progressHandler; .Rotate(rotateType, progressHandler)
.Flip(flipType, progressHandler);
try
{
return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
} }
} }
} }

Loading…
Cancel
Save