Browse Source

Move Resize and fix tests.

af/merge-core
James Jackson-South 9 years ago
parent
commit
d59e569ce8
  1. 77
      src/ImageSharp/Filters/Processors/Transforms/CompandingResizeProcessor.cs
  2. 2
      src/ImageSharp/Filters/Processors/Transforms/EntropyCropProcessor.cs
  3. 47
      src/ImageSharp/Filters/Processors/Transforms/ResamplingWeightedProcessor.cs
  4. 77
      src/ImageSharp/Filters/Processors/Transforms/ResizeProcessor.cs
  5. 2
      src/ImageSharp/Filters/Transforms/EntropyCrop.cs
  6. 6
      src/ImageSharp/Filters/Transforms/Resize.cs
  7. 5
      tests/ImageSharp.Tests/Processors/Samplers/ResizeTests.cs

77
src/ImageSharp/Samplers/Processors/Transforms/CompandingResizeProcessor.cs → src/ImageSharp/Filters/Processors/Transforms/CompandingResizeProcessor.cs

@ -22,11 +22,25 @@ namespace ImageSharp.Processors
/// <summary>
/// Initializes a new instance of the <see cref="CompandingResizeProcessor{TColor,TPacked}"/> class.
/// </summary>
/// <param name="sampler">
/// The sampler to perform the resize operation.
/// <param name="sampler">The sampler to perform the resize operation.</param>
/// <param name="width">The target width.</param>
/// <param name="height">The target height.</param>
public CompandingResizeProcessor(IResampler sampler, int width, int height)
: base(sampler, width, height, new Rectangle(0, 0, width, height))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CompandingResizeProcessor{TColor,TPacked}"/> class.
/// </summary>
/// <param name="sampler">The sampler to perform the resize operation.</param>
/// <param name="width">The target width.</param>
/// <param name="height">The target height.</param>
/// <param name="resizeRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the target image object to draw to.
/// </param>
public CompandingResizeProcessor(IResampler sampler)
: base(sampler)
public CompandingResizeProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
: base(sampler, width, height, resizeRectangle)
{
}
@ -34,37 +48,38 @@ namespace ImageSharp.Processors
public override bool Compand { get; set; } = true;
/// <inheritdoc/>
public override void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY)
{
// Jump out, we'll deal with that later.
if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle)
if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
{
return;
}
int width = target.Width;
int height = target.Height;
int sourceHeight = sourceRectangle.Height;
int targetX = target.Bounds.X;
int targetY = target.Bounds.Y;
int targetRight = target.Bounds.Right;
int targetBottom = target.Bounds.Bottom;
int startX = targetRectangle.X;
int endX = targetRectangle.Right;
int minX = Math.Max(targetX, startX);
int maxX = Math.Min(targetRight, endX);
int minY = Math.Max(targetY, startY);
int maxY = Math.Min(targetBottom, endY);
// Reset the values as the rectangle can be altered by ResizeRectangle.
startY = this.ResizeRectangle.Y;
endY = this.ResizeRectangle.Bottom;
int width = this.Width;
int height = this.Height;
int startX = this.ResizeRectangle.X;
int endX = this.ResizeRectangle.Right;
int minX = Math.Max(0, startX);
int maxX = Math.Min(width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(height, endY);
TColor[] target = new TColor[width * height];
if (this.Sampler is NearestNeighborResampler)
{
// Scaling factors
float widthFactor = sourceRectangle.Width / (float)targetRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)targetRectangle.Height;
float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock())
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock())
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock<TColor, TPacked>(width, height))
{
Parallel.For(
minY,
@ -84,6 +99,7 @@ namespace ImageSharp.Processors
}
// Break out now.
source.SetPixels(width, height, target);
return;
}
@ -91,19 +107,14 @@ namespace ImageSharp.Processors
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
Image<TColor, TPacked> firstPass = new Image<TColor, TPacked>(target.Width, source.Height);
TColor[] firstPass = new TColor[width * source.Height];
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock())
using (PixelAccessor<TColor, TPacked> firstPassPixels = firstPass.Lock())
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock())
using (PixelAccessor<TColor, TPacked> firstPassPixels = firstPass.Lock<TColor, TPacked>(width, source.Height))
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock<TColor, TPacked>(width, height))
{
minX = Math.Max(0, startX);
maxX = Math.Min(width, endX);
minY = Math.Max(0, startY);
maxY = Math.Min(height, endY);
Parallel.For(
0,
sourceHeight,
sourceRectangle.Height,
this.ParallelOptions,
y =>
{
@ -154,6 +165,8 @@ namespace ImageSharp.Processors
}
});
}
source.SetPixels(width, height, target);
}
}
}

2
src/ImageSharp/Filters/Processors/Transforms/EntropyCropProcessor.cs

@ -1,4 +1,4 @@
// <copyright file="EntropyCropProcessor.cs" company="James Jackson-South">
// <copyright file="EntropyCropProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>

47
src/ImageSharp/Samplers/Processors/Transforms/ResamplingWeightedProcessor.cs → src/ImageSharp/Filters/Processors/Transforms/ResamplingWeightedProcessor.cs

@ -13,21 +13,29 @@ namespace ImageSharp.Processors
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
public abstract class ResamplingWeightedProcessor<TColor, TPacked> : ImageSamplingProcessor<TColor, TPacked>
public abstract class ResamplingWeightedProcessor<TColor, TPacked> : ImageFilteringProcessor<TColor, TPacked>
where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="ResamplingWeightedProcessor{TColor, TPacked}"/> class.
/// </summary>
/// <param name="sampler">
/// The sampler to perform the resize operation.
/// <param name="sampler">The sampler to perform the resize operation.</param>
/// <param name="width">The target width.</param>
/// <param name="height">The target height.</param>
/// <param name="resizeRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the target image object to draw to.
/// </param>
protected ResamplingWeightedProcessor(IResampler sampler)
protected ResamplingWeightedProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
{
Guard.NotNull(sampler, nameof(sampler));
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
this.Sampler = sampler;
this.Width = width;
this.Height = height;
this.ResizeRectangle = resizeRectangle;
}
/// <summary>
@ -35,6 +43,21 @@ namespace ImageSharp.Processors
/// </summary>
public IResampler Sampler { get; }
/// <summary>
/// Gets the width.
/// </summary>
public int Width { get; }
/// <summary>
/// Gets the height.
/// </summary>
public int Height { get; }
/// <summary>
/// Gets the resize rectangle.
/// </summary>
public Rectangle ResizeRectangle { get; }
/// <summary>
/// Gets or sets the horizontal weights.
/// </summary>
@ -46,22 +69,12 @@ namespace ImageSharp.Processors
protected Weights[] VerticalWeights { get; set; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle)
protected override void OnApply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle)
{
if (!(this.Sampler is NearestNeighborResampler))
{
this.HorizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width);
this.VerticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height);
}
}
/// <inheritdoc/>
protected override void AfterApply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
// Copy the pixels over.
if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle)
{
target.ClonePixels(target.Width, target.Height, source.Pixels);
this.HorizontalWeights = this.PrecomputeWeights(this.ResizeRectangle.Width, sourceRectangle.Width);
this.VerticalWeights = this.PrecomputeWeights(this.ResizeRectangle.Height, sourceRectangle.Height);
}
}

77
src/ImageSharp/Samplers/Processors/Transforms/ResizeProcessor.cs → src/ImageSharp/Filters/Processors/Transforms/ResizeProcessor.cs

@ -24,46 +24,61 @@ namespace ImageSharp.Processors
/// <summary>
/// Initializes a new instance of the <see cref="ResizeProcessor{TColor, TPacked}"/> class.
/// </summary>
/// <param name="sampler">
/// The sampler to perform the resize operation.
/// <param name="sampler">The sampler to perform the resize operation.</param>
/// <param name="width">The target width.</param>
/// <param name="height">The target height.</param>
public ResizeProcessor(IResampler sampler, int width, int height)
: base(sampler, width, height, new Rectangle(0, 0, width, height))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeProcessor{TColor, TPacked}"/> class.
/// </summary>
/// <param name="sampler">The sampler to perform the resize operation.</param>
/// <param name="width">The target width.</param>
/// <param name="height">The target height.</param>
/// <param name="resizeRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the target image object to draw to.
/// </param>
public ResizeProcessor(IResampler sampler)
: base(sampler)
public ResizeProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
: base(sampler, width, height, resizeRectangle)
{
}
/// <inheritdoc/>
public override void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY)
{
// Jump out, we'll deal with that later.
if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle)
if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
{
return;
}
int width = target.Width;
int height = target.Height;
int sourceHeight = sourceRectangle.Height;
int targetX = target.Bounds.X;
int targetY = target.Bounds.Y;
int targetRight = target.Bounds.Right;
int targetBottom = target.Bounds.Bottom;
int startX = targetRectangle.X;
int endX = targetRectangle.Right;
int minX = Math.Max(targetX, startX);
int maxX = Math.Min(targetRight, endX);
int minY = Math.Max(targetY, startY);
int maxY = Math.Min(targetBottom, endY);
// Reset the values as the rectangle can be altered by ResizeRectangle.
startY = this.ResizeRectangle.Y;
endY = this.ResizeRectangle.Bottom;
int width = this.Width;
int height = this.Height;
int startX = this.ResizeRectangle.X;
int endX = this.ResizeRectangle.Right;
int minX = Math.Max(0, startX);
int maxX = Math.Min(width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(height, endY);
TColor[] target = new TColor[width * height];
if (this.Sampler is NearestNeighborResampler)
{
// Scaling factors
float widthFactor = sourceRectangle.Width / (float)targetRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)targetRectangle.Height;
float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock())
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock())
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock<TColor, TPacked>(width, height))
{
Parallel.For(
minY,
@ -83,6 +98,7 @@ namespace ImageSharp.Processors
}
// Break out now.
source.SetPixels(width, height, target);
return;
}
@ -90,19 +106,14 @@ namespace ImageSharp.Processors
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
Image<TColor, TPacked> firstPass = new Image<TColor, TPacked>(target.Width, source.Height);
TColor[] firstPass = new TColor[width * source.Height];
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock())
using (PixelAccessor<TColor, TPacked> firstPassPixels = firstPass.Lock())
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock())
using (PixelAccessor<TColor, TPacked> firstPassPixels = firstPass.Lock<TColor, TPacked>(width, source.Height))
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock<TColor, TPacked>(width, height))
{
minX = Math.Max(0, startX);
maxX = Math.Min(width, endX);
minY = Math.Max(0, startY);
maxY = Math.Min(height, endY);
Parallel.For(
0,
sourceHeight,
sourceRectangle.Height,
this.ParallelOptions,
y =>
{
@ -153,6 +164,8 @@ namespace ImageSharp.Processors
}
});
}
source.SetPixels(width, height, target);
}
}
}

2
src/ImageSharp/Filters/Transforms/EntropyCrop.cs

@ -1,4 +1,4 @@
// <copyright file="EntropyCrop.cs" company="James Jackson-South">
// <copyright file="EntropyCrop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>

6
src/ImageSharp/Samplers/Transforms/Resize.cs → src/ImageSharp/Filters/Transforms/Resize.cs

@ -155,14 +155,14 @@ namespace ImageSharp
if (compand)
{
processor = new CompandingResizeProcessor<TColor, TPacked>(sampler);
processor = new CompandingResizeProcessor<TColor, TPacked>(sampler, width, height, targetRectangle);
}
else
{
processor = new ResizeProcessor<TColor, TPacked>(sampler);
processor = new ResizeProcessor<TColor, TPacked>(sampler, width, height, targetRectangle);
}
return source.Process(width, height, sourceRectangle, targetRectangle, processor);
return source.Process(sourceRectangle, processor);
}
}
}

5
tests/ImageSharp.Tests/Processors/Samplers/ResizeTests.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Tests
{
using System;
using System.IO;
using Xunit;
@ -248,7 +249,7 @@ namespace ImageSharp.Tests
ResizeOptions options = new ResizeOptions()
{
Sampler = sampler,
Size = new Size(image.Width - 50, image.Height - 25),
Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * 95F)),
Mode = ResizeMode.Min
};
@ -276,7 +277,7 @@ namespace ImageSharp.Tests
ResizeOptions options = new ResizeOptions()
{
Sampler = sampler,
Size = new Size(image.Width - 200, image.Height),
Size = new Size(image.Width / 2, image.Height),
Mode = ResizeMode.Stretch
};

Loading…
Cancel
Save