Browse Source

Update RotateProcessor{TPixel}.cs

af/octree-no-pixelmap
James Jackson-South 6 years ago
parent
commit
98c8d4f3df
  1. 207
      src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs

207
src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs

@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -15,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
internal class RotateProcessor<TPixel> : AffineTransformProcessor<TPixel> internal class RotateProcessor<TPixel> : AffineTransformProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private float degrees;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RotateProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="RotateProcessor{TPixel}"/> class.
/// </summary> /// </summary>
@ -24,11 +28,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param> /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
public RotateProcessor(Configuration configuration, RotateProcessor definition, Image<TPixel> source, Rectangle sourceRectangle) public RotateProcessor(Configuration configuration, RotateProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, definition, source, sourceRectangle) : base(configuration, definition, source, sourceRectangle)
=> this.degrees = definition.Degrees;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{ {
this.Degrees = definition.Degrees; if (this.OptimizedApply(source, destination, this.Configuration))
} {
return;
}
private float Degrees { get; } base.OnFrameApply(source, destination);
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterImageApply(Image<TPixel> destination) protected override void AfterImageApply(Image<TPixel> destination)
@ -39,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return; return;
} }
if (MathF.Abs(WrapDegrees(this.Degrees)) < Constants.Epsilon) if (MathF.Abs(WrapDegrees(this.degrees)) < Constants.Epsilon)
{ {
// No need to do anything so return. // No need to do anything so return.
return; return;
@ -50,17 +61,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
base.AfterImageApply(destination); base.AfterImageApply(destination);
} }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{
if (this.OptimizedApply(source, destination, this.Configuration))
{
return;
}
base.OnFrameApply(source, destination);
}
/// <summary> /// <summary>
/// Wraps a given angle in degrees so that it falls withing the 0-360 degree range /// Wraps a given angle in degrees so that it falls withing the 0-360 degree range
/// </summary> /// </summary>
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Configuration configuration) Configuration configuration)
{ {
// Wrap the degrees to keep within 0-360 so we can apply optimizations when possible. // Wrap the degrees to keep within 0-360 so we can apply optimizations when possible.
float degrees = WrapDegrees(this.Degrees); float degrees = WrapDegrees(this.degrees);
if (MathF.Abs(degrees) < Constants.Epsilon) if (MathF.Abs(degrees) < Constants.Epsilon)
{ {
@ -131,25 +131,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
private void Rotate180(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private void Rotate180(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
int width = source.Width;
int height = source.Height;
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
source.Bounds(), source.Bounds(),
configuration, configuration,
rows => new Rotate180RowIntervalAction(source.Width, source.Height, source, destination));
{
for (int y = rows.Min; y < rows.Max; 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];
}
}
});
} }
/// <summary> /// <summary>
@ -160,31 +145,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
private void Rotate270(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private void Rotate270(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
int width = source.Width;
int height = source.Height;
Rectangle destinationBounds = destination.Bounds();
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
source.Bounds(), source.Bounds(),
configuration, configuration,
rows => new Rotate270RowIntervalAction(destination.Bounds(), source.Width, source.Height, source, destination));
{
for (int y = rows.Min; y < rows.Max; 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];
}
}
}
});
} }
/// <summary> /// <summary>
@ -195,28 +159,131 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
private void Rotate90(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private void Rotate90(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
int width = source.Width;
int height = source.Height;
Rectangle destinationBounds = destination.Bounds();
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
source.Bounds(), source.Bounds(),
configuration, configuration,
rows => new Rotate90RowIntervalAction(destination.Bounds(), source.Width, source.Height, source, destination));
}
private readonly struct Rotate180RowIntervalAction : IRowIntervalAction
{
private readonly int width;
private readonly int height;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public Rotate180RowIntervalAction(
int width,
int height,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{
this.width = width;
this.height = height;
this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows)
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(this.height - y - 1);
for (int x = 0; x < this.width; x++)
{
targetRow[this.width - x - 1] = sourceRow[x];
}
}
}
}
private readonly struct Rotate270RowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly int width;
private readonly int height;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public Rotate270RowIntervalAction(
Rectangle bounds,
int width,
int height,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{
this.bounds = bounds;
this.width = width;
this.height = height;
this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows)
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
for (int x = 0; x < this.width; x++)
{
int newX = this.height - y - 1;
newX = this.height - newX - 1;
int newY = this.width - x - 1;
if (this.bounds.Contains(newX, newY))
{
this.destination[newX, newY] = sourceRow[x];
}
}
}
}
}
private readonly struct Rotate90RowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly int width;
private readonly int height;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public Rotate90RowIntervalAction(
Rectangle bounds,
int width,
int height,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{
this.bounds = bounds;
this.width = width;
this.height = height;
this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows)
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
int newX = this.height - y - 1;
for (int x = 0; x < this.width; x++)
{ {
for (int y = rows.Min; y < rows.Max; y++) if (this.bounds.Contains(newX, x))
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); this.destination[newX, x] = sourceRow[x];
int newX = height - y - 1;
for (int x = 0; x < width; x++)
{
if (destinationBounds.Contains(newX, x))
{
destination[newX, x] = sourceRow[x];
}
}
} }
}); }
}
}
} }
} }
} }

Loading…
Cancel
Save