Browse Source

Merge remote-tracking branch 'refs/remotes/origin/Core' into Core-Flava

Former-commit-id: 6583ef8501a525fcc1c5103ad09dadea0045e574
Former-commit-id: 6e6ddc0dbf12d32958e50d9b6d04548d0bd5106b
Former-commit-id: 46c9e0018442621454a9ac461d04b218d39270ed
af/merge-core
James Jackson-South 10 years ago
parent
commit
215cfb0428
  1. 7
      README.md
  2. 8
      Rebracer.xml
  3. 2
      src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs
  4. 2
      src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs
  5. 2
      src/ImageProcessorCore/Filters/Processors/Binarization/ThresholdProcessor.cs
  6. 2
      src/ImageProcessorCore/Filters/Processors/BlendProcessor.cs
  7. 2
      src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs
  8. 15
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs
  9. 2
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs
  10. 2
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs
  11. 2
      src/ImageProcessorCore/Filters/Processors/ContrastProcessor.cs
  12. 3
      src/ImageProcessorCore/Filters/Processors/Convolution/BoxBlurProcessor.cs
  13. 2
      src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2DFilter.cs
  14. 43
      src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2PassFilter.cs
  15. 2
      src/ImageProcessorCore/Filters/Processors/Convolution/ConvolutionFilter.cs
  16. 3
      src/ImageProcessorCore/Filters/Processors/Convolution/GuassianBlurProcessor.cs
  17. 3
      src/ImageProcessorCore/Filters/Processors/Convolution/GuassianSharpenProcessor.cs
  18. 2
      src/ImageProcessorCore/Filters/Processors/GlowProcessor.cs
  19. 2
      src/ImageProcessorCore/Filters/Processors/InvertProcessor.cs
  20. 7
      src/ImageProcessorCore/Filters/Processors/PixelateProcessor.cs
  21. 2
      src/ImageProcessorCore/Filters/Processors/VignetteProcessor.cs
  22. 70
      src/ImageProcessorCore/ImageProcessor.cs
  23. 22
      src/ImageProcessorCore/PixelAccessor.cs
  24. 13
      src/ImageProcessorCore/Samplers/Processors/CropProcessor.cs
  25. 2
      src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs
  26. 2
      src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs
  27. 47
      src/ImageProcessorCore/Samplers/Processors/Matrix3x2Processor.cs
  28. 13
      src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs
  29. 3
      src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs
  30. 64
      src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs
  31. 68
      src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
  32. 4
      src/ImageProcessorCore/Samplers/Resamplers/CatmullRomResampler.cs
  33. 3
      src/ImageProcessorCore/Samplers/Resamplers/HermiteResampler.cs
  34. 1
      src/ImageProcessorCore/Samplers/Resamplers/Lanczos3Resampler.cs
  35. 1
      src/ImageProcessorCore/Samplers/Resamplers/Lanczos5Resampler.cs
  36. 1
      src/ImageProcessorCore/Samplers/Resamplers/Lanczos8Resampler.cs
  37. 11
      src/ImageProcessorCore/Samplers/Rotate.cs
  38. 11
      src/ImageProcessorCore/Samplers/Skew.cs
  39. 4
      tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

7
README.md

@ -34,11 +34,8 @@ We already have a [MyGet package repository](https://www.myget.org/gallery/image
If you prefer, you can compile ImageProcessorCore yourself (please do and help!), you'll need: If you prefer, you can compile ImageProcessorCore yourself (please do and help!), you'll need:
- Visual Studio 2015 (or above) - [Visual Studio 2015 with Update 3 (or above)](https://www.visualstudio.com/news/releasenotes/vs2015-update3-vs)
- The [.NET Core SDK Installer - The [.NET Core 1.0 SDK Installer](https://www.microsoft.com/net/core#windows) - Non VSCode link.
(Preview 1)](https://www.microsoft.com/net/download) - Click `.NET Core SDK Installer
(Preview 1)`
- The [.NET Core Tooling Preview 1 for Visual Studio 2015](https://dev.windows.com/en-us/downloads) - Click `.NET Core Tooling Preview 1 for Visual Studio 2015`.
To clone it locally click the "Clone in Windows" button above or run the following git commands. To clone it locally click the "Clone in Windows" button above or run the following git commands.

8
Rebracer.xml

@ -22,8 +22,12 @@
</ToolsOptionsCategory> </ToolsOptionsCategory>
<ToolsOptionsCategory name="TextEditor"> <ToolsOptionsCategory name="TextEditor">
<ToolsOptionsSubCategory name="CSharp-Specific"> <ToolsOptionsSubCategory name="CSharp-Specific">
<PropertyValue name="AddImport_SuggestForTypesInNuGetPackages">0</PropertyValue>
<PropertyValue name="AddImport_SuggestForTypesInReferenceAssemblies">0</PropertyValue>
<PropertyValue name="AutoComment">1</PropertyValue> <PropertyValue name="AutoComment">1</PropertyValue>
<PropertyValue name="ClosedFileDiagnostics">1</PropertyValue> <PropertyValue name="AutoInsertAsteriskForNewLinesOfBlockComments">1</PropertyValue>
<PropertyValue name="CSharpClosedFileDiagnostics">-1</PropertyValue>
<PropertyValue name="ClosedFileDiagnostics">-1</PropertyValue>
<PropertyValue name="DisplayLineSeparators">0</PropertyValue> <PropertyValue name="DisplayLineSeparators">0</PropertyValue>
<PropertyValue name="EnableHighlightRelatedKeywords">1</PropertyValue> <PropertyValue name="EnableHighlightRelatedKeywords">1</PropertyValue>
<PropertyValue name="ExtractMethod_AllowMovingDeclaration">0</PropertyValue> <PropertyValue name="ExtractMethod_AllowMovingDeclaration">0</PropertyValue>
@ -81,7 +85,7 @@
<PropertyValue name="Style_PreferIntrinsicPredefinedTypeKeywordInMemberAccess">1</PropertyValue> <PropertyValue name="Style_PreferIntrinsicPredefinedTypeKeywordInMemberAccess">1</PropertyValue>
<PropertyValue name="Style_QualifyMemberAccessWithThisOrMe">0</PropertyValue> <PropertyValue name="Style_QualifyMemberAccessWithThisOrMe">0</PropertyValue>
<PropertyValue name="Style_UseVarWhenDeclaringLocals">1</PropertyValue> <PropertyValue name="Style_UseVarWhenDeclaringLocals">1</PropertyValue>
<PropertyValue name="WarnOnBuildErrors">1</PropertyValue> <PropertyValue name="WarnOnBuildErrors">0</PropertyValue>
<PropertyValue name="Wrapping_IgnoreSpacesAroundBinaryOperators">0</PropertyValue> <PropertyValue name="Wrapping_IgnoreSpacesAroundBinaryOperators">0</PropertyValue>
<PropertyValue name="Wrapping_IgnoreSpacesAroundVariableDeclaration">0</PropertyValue> <PropertyValue name="Wrapping_IgnoreSpacesAroundVariableDeclaration">0</PropertyValue>
<PropertyValue name="Wrapping_KeepStatementsOnSingleLine">1</PropertyValue> <PropertyValue name="Wrapping_KeepStatementsOnSingleLine">1</PropertyValue>

2
src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// An <see cref="IImageProcessor"/> to change the Alpha of an <see cref="Image"/>. /// An <see cref="IImageProcessor"/> to change the Alpha of an <see cref="Image"/>.
/// </summary> /// </summary>
public class AlphaProcessor : ParallelImageProcessor public class AlphaProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AlphaProcessor"/> class. /// Initializes a new instance of the <see cref="AlphaProcessor"/> class.

2
src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs

@ -11,7 +11,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Sets the background color of the image. /// Sets the background color of the image.
/// </summary> /// </summary>
public class BackgroundColorProcessor : ParallelImageProcessor public class BackgroundColorProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// The epsilon for comparing floating point numbers. /// The epsilon for comparing floating point numbers.

2
src/ImageProcessorCore/Filters/Processors/Binarization/ThresholdProcessor.cs

@ -13,7 +13,7 @@ namespace ImageProcessorCore.Processors
/// <see cref="Image"/>. The image will be converted to greyscale before thresholding /// <see cref="Image"/>. The image will be converted to greyscale before thresholding
/// occurs. /// occurs.
/// </summary> /// </summary>
public class ThresholdProcessor : ParallelImageProcessor public class ThresholdProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ThresholdProcessor"/> class. /// Initializes a new instance of the <see cref="ThresholdProcessor"/> class.

2
src/ImageProcessorCore/Filters/Processors/BlendProcessor.cs

@ -10,7 +10,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Combines two images together by blending the pixels. /// Combines two images together by blending the pixels.
/// </summary> /// </summary>
public class BlendProcessor : ParallelImageProcessor public class BlendProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// The image to blend. /// The image to blend.

2
src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// An <see cref="IImageProcessor"/> to change the brightness of an <see cref="Image"/>. /// An <see cref="IImageProcessor"/> to change the brightness of an <see cref="Image"/>.
/// </summary> /// </summary>
public class BrightnessProcessor : ParallelImageProcessor public class BrightnessProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BrightnessProcessor"/> class. /// Initializes a new instance of the <see cref="BrightnessProcessor"/> class.

15
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs

@ -11,7 +11,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// The color matrix filter. /// The color matrix filter.
/// </summary> /// </summary>
public abstract class ColorMatrixFilter : ParallelImageProcessor, IColorMatrixFilter public abstract class ColorMatrixFilter : ImageProcessor, IColorMatrixFilter
{ {
/// <inheritdoc/> /// <inheritdoc/>
public abstract Matrix4x4 Matrix { get; } public abstract Matrix4x4 Matrix { get; }
@ -22,8 +22,6 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{ {
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X; int startX = sourceRectangle.X;
int endX = sourceRectangle.Right; int endX = sourceRectangle.Right;
Matrix4x4 matrix = this.Matrix; Matrix4x4 matrix = this.Matrix;
@ -36,15 +34,12 @@ namespace ImageProcessorCore.Processors
endY, endY,
y => y =>
{ {
if (y >= sourceY && y < sourceBottom) for (int x = startX; x < endX; x++)
{ {
for (int x = startX; x < endX; x++) targetPixels[x, y] = this.ApplyMatrix(sourcePixels[x, y], matrix);
{
targetPixels[x, y] = this.ApplyMatrix(sourcePixels[x, y], matrix);
}
this.OnRowProcessed();
} }
this.OnRowProcessed();
}); });
} }
} }

2
src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs

@ -24,7 +24,7 @@ namespace ImageProcessorCore.Processors
}; };
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
new VignetteProcessor { Color = new Color(0, 10 / 255f, 0) }.Apply(target, target, targetRectangle); new VignetteProcessor { Color = new Color(0, 10 / 255f, 0) }.Apply(target, target, targetRectangle);
} }

2
src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs

@ -30,7 +30,7 @@ namespace ImageProcessorCore.Processors
}; };
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
new VignetteProcessor { Color = new Color(102 / 255f, 34 / 255f, 0) }.Apply(target, target, targetRectangle); new VignetteProcessor { Color = new Color(102 / 255f, 34 / 255f, 0) }.Apply(target, target, targetRectangle);
new GlowProcessor new GlowProcessor

2
src/ImageProcessorCore/Filters/Processors/ContrastProcessor.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// An <see cref="IImageProcessor"/> to change the contrast of an <see cref="Image"/>. /// An <see cref="IImageProcessor"/> to change the contrast of an <see cref="Image"/>.
/// </summary> /// </summary>
public class ContrastProcessor : ParallelImageProcessor public class ContrastProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContrastProcessor"/> class. /// Initializes a new instance of the <see cref="ContrastProcessor"/> class.

3
src/ImageProcessorCore/Filters/Processors/Convolution/BoxBlurProcessor.cs

@ -42,9 +42,6 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
public override float[,] KernelY => this.kernelY; public override float[,] KernelY => this.kernelY;
/// <inheritdoc/>
public override int Parallelism => 1;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {

2
src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2DFilter.cs

@ -11,7 +11,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Defines a filter that uses two one-dimensional matrices to perform convolution against an image. /// Defines a filter that uses two one-dimensional matrices to perform convolution against an image.
/// </summary> /// </summary>
public abstract class Convolution2DFilter : ParallelImageProcessor public abstract class Convolution2DFilter : ImageProcessor
{ {
/// <summary> /// <summary>
/// Gets the horizontal gradient operator. /// Gets the horizontal gradient operator.

43
src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2PassFilter.cs

@ -10,7 +10,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Defines a filter that uses two one-dimensional matrices to perform two-pass convolution against an image. /// Defines a filter that uses two one-dimensional matrices to perform two-pass convolution against an image.
/// </summary> /// </summary>
public abstract class Convolution2PassFilter : ParallelImageProcessor public abstract class Convolution2PassFilter : ImageProcessor
{ {
/// <summary> /// <summary>
/// Gets the horizontal gradient operator. /// Gets the horizontal gradient operator.
@ -64,7 +64,6 @@ namespace ImageProcessorCore.Processors
int radiusY = kernelHeight >> 1; int radiusY = kernelHeight >> 1;
int radiusX = kernelWidth >> 1; int radiusX = kernelWidth >> 1;
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom; int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X; int startX = sourceRectangle.X;
int endX = sourceRectangle.Right; int endX = sourceRectangle.Right;
@ -79,36 +78,34 @@ namespace ImageProcessorCore.Processors
endY, endY,
y => y =>
{ {
if (y >= sourceY && y < sourceBottom) for (int x = startX; x < endX; x++)
{ {
for (int x = startX; x < endX; x++) Color destination = new Color();
{
Color destination = new Color();
// Apply each matrix multiplier to the color components for each pixel. // Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelHeight; fy++) for (int fy = 0; fy < kernelHeight; fy++)
{ {
int fyr = fy - radiusY; int fyr = fy - radiusY;
int offsetY = y + fyr; int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY); offsetY = offsetY.Clamp(0, maxY);
for (int fx = 0; fx < kernelWidth; fx++) for (int fx = 0; fx < kernelWidth; fx++)
{ {
int fxr = fx - radiusX; int fxr = fx - radiusX;
int offsetX = x + fxr; int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX); offsetX = offsetX.Clamp(0, maxX);
Color currentColor = sourcePixels[offsetX, offsetY]; Color currentColor = sourcePixels[offsetX, offsetY];
destination += kernel[fy, fx] * currentColor; destination += kernel[fy, fx] * currentColor;
}
} }
targetPixels[x, y] = destination;
} }
this.OnRowProcessed();
targetPixels[x, y] = destination;
} }
this.OnRowProcessed();
}); });
} }
} }

2
src/ImageProcessorCore/Filters/Processors/Convolution/ConvolutionFilter.cs

@ -10,7 +10,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Defines a filter that uses a 2 dimensional matrix to perform convolution against an image. /// Defines a filter that uses a 2 dimensional matrix to perform convolution against an image.
/// </summary> /// </summary>
public abstract class ConvolutionFilter : ParallelImageProcessor public abstract class ConvolutionFilter : ImageProcessor
{ {
/// <summary> /// <summary>
/// Gets the 2d gradient operator. /// Gets the 2d gradient operator.

3
src/ImageProcessorCore/Filters/Processors/Convolution/GuassianBlurProcessor.cs

@ -76,9 +76,6 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
public override float[,] KernelY => this.kernelY; public override float[,] KernelY => this.kernelY;
/// <inheritdoc/>
public override int Parallelism => 1;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {

3
src/ImageProcessorCore/Filters/Processors/Convolution/GuassianSharpenProcessor.cs

@ -78,9 +78,6 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
public override float[,] KernelY => this.kernelY; public override float[,] KernelY => this.kernelY;
/// <inheritdoc/>
public override int Parallelism => 1;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {

2
src/ImageProcessorCore/Filters/Processors/GlowProcessor.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Creates a glow effect on the image /// Creates a glow effect on the image
/// </summary> /// </summary>
public class GlowProcessor : ParallelImageProcessor public class GlowProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Gets or sets the glow color to apply. /// Gets or sets the glow color to apply.

2
src/ImageProcessorCore/Filters/Processors/InvertProcessor.cs

@ -11,7 +11,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// An <see cref="IImageProcessor"/> to invert the colors of an <see cref="Image"/>. /// An <see cref="IImageProcessor"/> to invert the colors of an <see cref="Image"/>.
/// </summary> /// </summary>
public class InvertProcessor : ParallelImageProcessor public class InvertProcessor : ImageProcessor
{ {
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)

7
src/ImageProcessorCore/Filters/Processors/PixelateProcessor.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// An <see cref="IImageProcessor"/> to invert the colors of an <see cref="Image"/>. /// An <see cref="IImageProcessor"/> to invert the colors of an <see cref="Image"/>.
/// </summary> /// </summary>
public class PixelateProcessor : ParallelImageProcessor public class PixelateProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PixelateProcessor"/> class. /// Initializes a new instance of the <see cref="PixelateProcessor"/> class.
@ -27,9 +27,6 @@ namespace ImageProcessorCore.Processors
this.Value = size; this.Value = size;
} }
/// <inheritdoc/>
public override int Parallelism { get; set; } = 1;
/// <summary> /// <summary>
/// Gets or the pixel size. /// Gets or the pixel size.
/// </summary> /// </summary>
@ -59,7 +56,6 @@ namespace ImageProcessorCore.Processors
{ {
for (int x = startX; x < endX; x += size) for (int x = startX; x < endX; x += size)
{ {
int offsetX = offset; int offsetX = offset;
int offsetY = offset; int offsetY = offset;
@ -88,6 +84,7 @@ namespace ImageProcessorCore.Processors
} }
} }
} }
this.OnRowProcessed(); this.OnRowProcessed();
} }
}); });

2
src/ImageProcessorCore/Filters/Processors/VignetteProcessor.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Creates a vignette effect on the image /// Creates a vignette effect on the image
/// </summary> /// </summary>
public class VignetteProcessor : ParallelImageProcessor public class VignetteProcessor : ImageProcessor
{ {
/// <summary> /// <summary>
/// Gets or sets the vignette color to apply. /// Gets or sets the vignette color to apply.

70
src/ImageProcessorCore/ParallelImageProcessor.cs → src/ImageProcessorCore/ImageProcessor.cs

@ -1,4 +1,4 @@
// <copyright file="ParallelImageProcessor.cs" company="James Jackson-South"> // <copyright file="ImageProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -7,21 +7,15 @@ namespace ImageProcessorCore.Processors
{ {
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
/// <summary> /// <summary>
/// Allows the application of processors using parallel processing. /// Allows the application of processors to images.
/// </summary> /// </summary>
public abstract class ParallelImageProcessor : IImageProcessor public abstract class ImageProcessor : IImageProcessor
{ {
/// <inheritdoc/> /// <inheritdoc/>
public event ProgressEventHandler OnProgress; public event ProgressEventHandler OnProgress;
/// <summary>
/// Gets or sets the count of workers to run the process in parallel.
/// </summary>
public virtual int Parallelism { get; set; } = Environment.ProcessorCount * 2;
/// <summary> /// <summary>
/// The number of rows processed by a derived class. /// The number of rows processed by a derived class.
/// </summary> /// </summary>
@ -42,34 +36,7 @@ namespace ImageProcessorCore.Processors
this.numRowsProcessed = 0; this.numRowsProcessed = 0;
this.totalRows = sourceRectangle.Height; this.totalRows = sourceRectangle.Height;
if (this.Parallelism > 1) this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom);
{
int partitionCount = this.Parallelism;
Task[] tasks = new Task[partitionCount];
for (int p = 0; p < partitionCount; p++)
{
int current = p;
tasks[p] = Task.Run(
() =>
{
int batchSize = sourceRectangle.Height / partitionCount;
int yStart = sourceRectangle.Y + (current * batchSize);
int yEnd = current == partitionCount - 1
? sourceRectangle.Bottom
: yStart + batchSize;
this.Apply(target, source, target.Bounds, sourceRectangle, yStart, yEnd);
});
}
Task.WaitAll(tasks);
}
else
{
this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom);
}
this.AfterApply(target, source, target.Bounds, sourceRectangle); this.AfterApply(target, source, target.Bounds, sourceRectangle);
} }
@ -88,6 +55,7 @@ namespace ImageProcessorCore.Processors
float[] pixels = new float[width * height * 4]; float[] pixels = new float[width * height * 4];
target.SetPixels(width, height, pixels); target.SetPixels(width, height, pixels);
// Ensure we always have bounds.
if (sourceRectangle == Rectangle.Empty) if (sourceRectangle == Rectangle.Empty)
{ {
sourceRectangle = source.Bounds; sourceRectangle = source.Bounds;
@ -101,33 +69,9 @@ namespace ImageProcessorCore.Processors
this.OnApply(target, source, targetRectangle, sourceRectangle); this.OnApply(target, source, targetRectangle, sourceRectangle);
this.numRowsProcessed = 0; this.numRowsProcessed = 0;
this.totalRows = targetRectangle.Bottom; this.totalRows = targetRectangle.Height;
if (this.Parallelism > 1) this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom);
{
int partitionCount = this.Parallelism;
Task[] tasks = new Task[partitionCount];
for (int p = 0; p < partitionCount; p++)
{
int current = p;
tasks[p] = Task.Run(() =>
{
int batchSize = targetRectangle.Bottom / partitionCount;
int yStart = current * batchSize;
int yEnd = current == partitionCount - 1 ? targetRectangle.Bottom : yStart + batchSize;
this.Apply(target, source, targetRectangle, sourceRectangle, yStart, yEnd);
});
}
Task.WaitAll(tasks);
}
else
{
this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom);
}
this.AfterApply(target, source, target.Bounds, sourceRectangle); this.AfterApply(target, source, target.Bounds, sourceRectangle);
} }

22
src/ImageProcessorCore/PixelAccessor.cs

@ -16,7 +16,7 @@ namespace ImageProcessorCore
/// <summary> /// <summary>
/// The position of the first pixel in the bitmap. /// The position of the first pixel in the bitmap.
/// </summary> /// </summary>
private float* pixelsBase; private Color* pixelsBase;
/// <summary> /// <summary>
/// Provides a way to access the pixels from unmanaged memory. /// Provides a way to access the pixels from unmanaged memory.
@ -48,24 +48,12 @@ namespace ImageProcessorCore
Guard.MustBeGreaterThan(image.Width, 0, "image width"); Guard.MustBeGreaterThan(image.Width, 0, "image width");
Guard.MustBeGreaterThan(image.Height, 0, "image height"); Guard.MustBeGreaterThan(image.Height, 0, "image height");
int size = image.Pixels.Length;
this.Width = image.Width; this.Width = image.Width;
this.Height = image.Height; this.Height = image.Height;
// Assign the pointer. // Assign the pointer.
// If buffer is allocated on Large Object Heap i.e > 85Kb, then we are going to pin it instead of making a copy. this.pixelsHandle = GCHandle.Alloc(image.Pixels, GCHandleType.Pinned);
if (size > 87040) this.pixelsBase = (Color*)this.pixelsHandle.AddrOfPinnedObject().ToPointer();
{
this.pixelsHandle = GCHandle.Alloc(image.Pixels, GCHandleType.Pinned);
this.pixelsBase = (float*)this.pixelsHandle.AddrOfPinnedObject().ToPointer();
}
else
{
fixed (float* pbuffer = image.Pixels)
{
this.pixelsBase = pbuffer;
}
}
} }
/// <summary> /// <summary>
@ -113,7 +101,7 @@ namespace ImageProcessorCore
throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height.");
} }
#endif #endif
return *((Color*)(this.pixelsBase + ((y * this.Width) + x) * 4)); return *(this.pixelsBase + ((y * this.Width) + x));
} }
set set
@ -129,7 +117,7 @@ namespace ImageProcessorCore
throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height.");
} }
#endif #endif
*(Color*)(this.pixelsBase + (((y * this.Width) + x) * 4)) = value; *(this.pixelsBase + ((y * this.Width) + x)) = value;
} }
} }

13
src/ImageProcessorCore/Samplers/Processors/CropProcessor.cs

@ -15,8 +15,6 @@ namespace ImageProcessorCore.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{ {
int targetY = targetRectangle.Y;
int targetBottom = targetRectangle.Bottom;
int startX = targetRectangle.X; int startX = targetRectangle.X;
int endX = targetRectangle.Right; int endX = targetRectangle.Right;
int sourceX = sourceRectangle.X; int sourceX = sourceRectangle.X;
@ -30,15 +28,12 @@ namespace ImageProcessorCore.Processors
endY, endY,
y => y =>
{ {
if (y >= targetY && y < targetBottom) for (int x = startX; x < endX; x++)
{ {
for (int x = startX; x < endX; x++) targetPixels[x, y] = sourcePixels[x + sourceX, y + sourceY];
{
targetPixels[x, y] = sourcePixels[x + sourceX, y + sourceY];
}
this.OnRowProcessed();
} }
this.OnRowProcessed();
}); });
} }
} }

2
src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs

@ -92,7 +92,7 @@ namespace ImageProcessorCore.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
// Copy the pixels over. // Copy the pixels over.
if (source.Bounds == target.Bounds) if (source.Bounds == target.Bounds)

2
src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs

@ -9,7 +9,7 @@ namespace ImageProcessorCore.Processors
/// Applies sampling methods to an image. /// Applies sampling methods to an image.
/// All processors requiring resampling or resizing should inherit from this. /// All processors requiring resampling or resizing should inherit from this.
/// </summary> /// </summary>
public abstract class ImageSampler : ParallelImageProcessor, IImageSampler public abstract class ImageSampler : ImageProcessor, IImageSampler
{ {
/// <inheritdoc/> /// <inheritdoc/>
public virtual bool Compand { get; set; } = false; public virtual bool Compand { get; set; } = false;

47
src/ImageProcessorCore/Samplers/Processors/Matrix3x2Processor.cs

@ -0,0 +1,47 @@
// <copyright file="Matrix3x2Processor.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.Numerics;
/// <summary>
/// Provides methods to transform an image using a <see cref="Matrix3x2"/>.
/// </summary>
public abstract class Matrix3x2Processor : ImageSampler
{
/// <summary>
/// Creates a new target to contain the results of the matrix transform.
/// </summary>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="sourceRectangle">The source rectangle.</param>
/// <param name="processMatrix">The processing matrix.</param>
protected static void CreateNewTarget(ImageBase target, Rectangle sourceRectangle, Matrix3x2 processMatrix)
{
Matrix3x2 sizeMatrix;
if (Matrix3x2.Invert(processMatrix, out sizeMatrix))
{
Rectangle rectangle = ImageMaths.GetBoundingRectangle(sourceRectangle, sizeMatrix);
target.SetPixels(rectangle.Width, rectangle.Height, new float[rectangle.Width * rectangle.Height * 4]);
}
}
/// <summary>
/// Gets a transform matrix adjusted to center upon the target image bounds.
/// </summary>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image.</param>
/// <param name="matrix">The transform matrix.</param>
/// <returns>
/// The <see cref="Matrix3x2"/>.
/// </returns>
protected static Matrix3x2 GetCenteredMatrix(ImageBase target, ImageBase source, Matrix3x2 matrix)
{
Matrix3x2 translationToTargetCenter = Matrix3x2.CreateTranslation(-target.Width / 2f, -target.Height / 2f);
Matrix3x2 translateToSourceCenter = Matrix3x2.CreateTranslation(source.Width / 2f, source.Height / 2f);
return (translationToTargetCenter * matrix) * translateToSourceCenter;
}
}
}

13
src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs

@ -31,9 +31,6 @@ namespace ImageProcessorCore.Processors
this.Sampler = sampler; this.Sampler = sampler;
} }
/// <inheritdoc/>
public override int Parallelism { get; set; } = 1;
/// <summary> /// <summary>
/// Gets the sampler to perform the resize operation. /// Gets the sampler to perform the resize operation.
/// </summary> /// </summary>
@ -62,13 +59,7 @@ namespace ImageProcessorCore.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply( protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
ImageBase target,
ImageBase source,
Rectangle targetRectangle,
Rectangle sourceRectangle,
int startY,
int endY)
{ {
// Jump out, we'll deal with that later. // Jump out, we'll deal with that later.
if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle)
@ -217,7 +208,7 @@ namespace ImageProcessorCore.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
// Copy the pixels over. // Copy the pixels over.
if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle)

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

@ -34,9 +34,6 @@ namespace ImageProcessorCore.Processors
/// </summary> /// </summary>
public RotateType RotateType { get; } public RotateType RotateType { get; }
/// <inheritdoc/>
public override int Parallelism { get; set; } = 1;
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{ {

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

@ -11,85 +11,57 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Provides methods that allow the rotating of images. /// Provides methods that allow the rotating of images.
/// </summary> /// </summary>
public class RotateProcessor : ImageSampler public class RotateProcessor : Matrix3x2Processor
{ {
/// <inheritdoc/>
public override int Parallelism { get; set; } = 1;
/// <summary> /// <summary>
/// Gets or sets the angle of rotation in degrees. /// The tranform matrix to apply.
/// </summary> /// </summary>
public float Angle { get; set; } private Matrix3x2 processMatrix;
/// <summary> /// <summary>
/// Gets or sets the center point. /// Gets or sets the angle of processMatrix in degrees.
/// </summary> /// </summary>
public Point Center { get; set; } public float Angle { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to expand the canvas to fit the rotated image. /// Gets or sets a value indicating whether to expand the canvas to fit the rotated image.
/// </summary> /// </summary>
public bool Expand { get; set; } public bool Expand { get; set; } = true;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
processMatrix = Point.CreateRotation(new Point(0, 0), -this.Angle);
if (this.Expand) if (this.Expand)
{ {
Point centre = this.Center == Point.Empty ? Rectangle.Center(sourceRectangle) : this.Center; CreateNewTarget(target, sourceRectangle, processMatrix);
Matrix3x2 rotation = Point.CreateRotation(centre, -this.Angle);
Matrix3x2 invertedRotation;
Matrix3x2.Invert(rotation, out invertedRotation);
Rectangle bounds = ImageMaths.GetBoundingRectangle(source.Bounds, invertedRotation);
target.SetPixels(bounds.Width, bounds.Height, new float[bounds.Width * bounds.Height * 4]);
} }
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{ {
int height = target.Height; Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix);
int startX = 0;
int endX = target.Width;
Point centre = this.Center == Point.Empty ? Rectangle.Center(target.Bounds) : this.Center;
//Matrix3x2 invertedRotation;
Matrix3x2 rotation = Point.CreateRotation(centre, -this.Angle);
//Matrix3x2.Invert(rotation, out invertedRotation);
//Vector2 rightTop = Vector2.Transform(new Vector2(source.Width, 0), invertedRotation);
//Vector2 leftBottom = Vector2.Transform(new Vector2(0, source.Height), invertedRotation);
//if (this.Angle < 0)
//{
// rotation = Point.CreateRotation(new Point((int)-leftBottom.X, (int)leftBottom.Y), -this.Angle);
//}
//if (this.Angle > 0)
//{
// rotation = Point.CreateRotation(new Point((int)rightTop.X, (int)-rightTop.Y), -this.Angle);
//}
// Since we are not working in parallel we use full height and width
// of the first pass image.
using (PixelAccessor sourcePixels = source.Lock()) using (PixelAccessor sourcePixels = source.Lock())
using (PixelAccessor targetPixels = target.Lock()) using (PixelAccessor targetPixels = target.Lock())
{ {
Parallel.For( Parallel.For(
0, 0,
height, target.Height,
y => y =>
{
for (int x = 0; x < target.Width; x++)
{ {
for (int x = startX; x < endX; x++) Point transformedPoint = Point.Rotate(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
{ {
Point rotated = Point.Rotate(new Point(x, y), rotation); targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
if (source.Bounds.Contains(rotated.X, rotated.Y))
{
targetPixels[x, y] = sourcePixels[rotated.X, rotated.Y];
}
} }
}
this.OnRowProcessed(); OnRowProcessed();
}); });
} }
} }
} }

68
src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs

@ -11,10 +11,12 @@ namespace ImageProcessorCore.Processors
/// <summary> /// <summary>
/// Provides methods that allow the skewing of images. /// Provides methods that allow the skewing of images.
/// </summary> /// </summary>
public class SkewProcessor : ImageSampler public class SkewProcessor : Matrix3x2Processor
{ {
/// <inheritdoc/> /// <summary>
public override int Parallelism { get; set; } = 1; /// The tranform matrix to apply.
/// </summary>
private Matrix3x2 processMatrix;
/// <summary> /// <summary>
/// Gets or sets the angle of rotation along the x-axis in degrees. /// Gets or sets the angle of rotation along the x-axis in degrees.
@ -26,77 +28,45 @@ namespace ImageProcessorCore.Processors
/// </summary> /// </summary>
public float AngleY { get; set; } public float AngleY { get; set; }
/// <summary>
/// Gets or sets the center point.
/// </summary>
public Point Center { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to expand the canvas to fit the skewed image. /// Gets or sets a value indicating whether to expand the canvas to fit the skewed image.
/// </summary> /// </summary>
public bool Expand { get; set; } public bool Expand { get; set; } = true;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{ {
this.processMatrix = Point.CreateSkew(new Point(0, 0), -this.AngleX, -this.AngleY);
if (this.Expand) if (this.Expand)
{ {
Point centre = this.Center; CreateNewTarget(target, sourceRectangle, this.processMatrix);
Matrix3x2 skew = Point.CreateSkew(centre, -this.AngleX, -this.AngleY);
Matrix3x2 invertedSkew;
Matrix3x2.Invert(skew, out invertedSkew);
Rectangle bounds = ImageMaths.GetBoundingRectangle(source.Bounds, invertedSkew);
target.SetPixels(bounds.Width, bounds.Height, new float[bounds.Width * bounds.Height * 4]);
} }
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{ {
int height = target.Height; Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix);
int startX = 0;
int endX = target.Width;
Point centre = this.Center;
Matrix3x2 invertedSkew;
Matrix3x2 skew = Point.CreateSkew(centre, -this.AngleX, -this.AngleY);
Matrix3x2.Invert(skew, out invertedSkew);
Vector2 rightTop = Vector2.Transform(new Vector2(source.Width, 0), invertedSkew);
Vector2 leftBottom = Vector2.Transform(new Vector2(0, source.Height), invertedSkew);
if (this.AngleX < 0 && this.AngleY > 0)
{
skew = Point.CreateSkew(new Point((int)-leftBottom.X, (int)leftBottom.Y), -this.AngleX, -this.AngleY);
}
if (this.AngleX > 0 && this.AngleY < 0)
{
skew = Point.CreateSkew(new Point((int)rightTop.X, (int)-rightTop.Y), -this.AngleX, -this.AngleY);
}
if (this.AngleX < 0 && this.AngleY < 0)
{
skew = Point.CreateSkew(new Point(target.Width - 1, target.Height - 1), -this.AngleX, -this.AngleY);
}
using (PixelAccessor sourcePixels = source.Lock()) using (PixelAccessor sourcePixels = source.Lock())
using (PixelAccessor targetPixels = target.Lock()) using (PixelAccessor targetPixels = target.Lock())
{ {
Parallel.For( Parallel.For(
0, 0,
height, target.Height,
y => y =>
{
for (int x = startX; x < endX; x++)
{ {
Point skewed = Point.Skew(new Point(x, y), skew); for (int x = 0; x < target.Width; x++)
if (source.Bounds.Contains(skewed.X, skewed.Y))
{ {
targetPixels[x, y] = sourcePixels[skewed.X, skewed.Y]; 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];
}
} }
}
this.OnRowProcessed(); OnRowProcessed();
}); });
} }
} }
} }

4
src/ImageProcessorCore/Samplers/Resamplers/CatmullRomResampler.cs

@ -6,7 +6,9 @@
namespace ImageProcessorCore namespace ImageProcessorCore
{ {
/// <summary> /// <summary>
/// The function implements the Catmull-Rom algorithm. /// The Catmull-Rom filter is a well known standard Cubic Filter often used as a interpolation function.
/// This filter produces a reasonably sharp edge, but without a the pronounced gradient change on large
/// scale image enlargements that a 'Lagrange' filter can produce.
/// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/> /// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/>
/// </summary> /// </summary>
public class CatmullRomResampler : IResampler public class CatmullRomResampler : IResampler

3
src/ImageProcessorCore/Samplers/Resamplers/HermiteResampler.cs

@ -6,7 +6,8 @@
namespace ImageProcessorCore.Processors namespace ImageProcessorCore.Processors
{ {
/// <summary> /// <summary>
/// The function implements the hermite algorithm. /// The Hermite filter is type of smoothed triangular interpolation Filter,
/// This filter rounds off strong edges while preserving flat 'color levels' in the original image.
/// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/> /// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/>
/// </summary> /// </summary>
public class HermiteResampler : IResampler public class HermiteResampler : IResampler

1
src/ImageProcessorCore/Samplers/Resamplers/Lanczos3Resampler.cs

@ -8,6 +8,7 @@ namespace ImageProcessorCore
/// <summary> /// <summary>
/// The function implements the Lanczos kernel algorithm as described on /// The function implements the Lanczos kernel algorithm as described on
/// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see> /// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see>
/// with a radius of 3 pixels.
/// </summary> /// </summary>
public class Lanczos3Resampler : IResampler public class Lanczos3Resampler : IResampler
{ {

1
src/ImageProcessorCore/Samplers/Resamplers/Lanczos5Resampler.cs

@ -8,6 +8,7 @@ namespace ImageProcessorCore
/// <summary> /// <summary>
/// The function implements the Lanczos kernel algorithm as described on /// The function implements the Lanczos kernel algorithm as described on
/// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see> /// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see>
/// with a radius of 5 pixels.
/// </summary> /// </summary>
public class Lanczos5Resampler : IResampler public class Lanczos5Resampler : IResampler
{ {

1
src/ImageProcessorCore/Samplers/Resamplers/Lanczos8Resampler.cs

@ -8,6 +8,7 @@ namespace ImageProcessorCore
/// <summary> /// <summary>
/// The function implements the Lanczos kernel algorithm as described on /// The function implements the Lanczos kernel algorithm as described on
/// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see> /// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see>
/// with a radius of 8 pixels.
/// </summary> /// </summary>
public class Lanczos8Resampler : IResampler public class Lanczos8Resampler : IResampler
{ {

11
src/ImageProcessorCore/Samplers/Rotate.cs

@ -1,7 +1,7 @@
// <copyright file="Rotate.cs" company="James Jackson-South"> // <copyright file="Rotate.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>------------------------------------------------------------------------------------------------------------------- // </copyright>
namespace ImageProcessorCore namespace ImageProcessorCore
{ {
@ -21,21 +21,20 @@ namespace ImageProcessorCore
/// <returns>The <see cref="Image"/></returns> /// <returns>The <see cref="Image"/></returns>
public static Image Rotate(this Image source, float degrees, ProgressEventHandler progressHandler = null) public static Image Rotate(this Image source, float degrees, ProgressEventHandler progressHandler = null)
{ {
return Rotate(source, degrees, Point.Empty, true, progressHandler); return Rotate(source, degrees, true, progressHandler);
} }
/// <summary> /// <summary>
/// Rotates an image by the given angle in degrees around the given center point. /// Rotates an image by the given angle in degrees.
/// </summary> /// </summary>
/// <param name="source">The image to rotate.</param> /// <param name="source">The image to rotate.</param>
/// <param name="degrees">The angle in degrees to perform the rotation.</param> /// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <param name="center">The center point at which to rotate the image.</param>
/// <param name="expand">Whether to expand the image to fit the rotated result.</param> /// <param name="expand">Whether to expand the image to fit the rotated result.</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>
public static Image Rotate(this Image source, float degrees, Point center, bool expand, ProgressEventHandler progressHandler = null) public static Image Rotate(this Image source, float degrees, bool expand, ProgressEventHandler progressHandler = null)
{ {
RotateProcessor processor = new RotateProcessor { Angle = degrees, Center = center, Expand = expand }; RotateProcessor processor = new RotateProcessor { Angle = degrees, Expand = expand };
processor.OnProgress += progressHandler; processor.OnProgress += progressHandler;
try try

11
src/ImageProcessorCore/Samplers/Skew.cs

@ -1,7 +1,7 @@
// <copyright file="Skew.cs" company="James Jackson-South"> // <copyright file="Skew.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>------------------------------------------------------------------------------------------------------------------- // </copyright>
namespace ImageProcessorCore namespace ImageProcessorCore
{ {
@ -22,22 +22,21 @@ namespace ImageProcessorCore
/// <returns>The <see cref="Image"/></returns> /// <returns>The <see cref="Image"/></returns>
public static Image Skew(this Image source, float degreesX, float degreesY, ProgressEventHandler progressHandler = null) public static Image Skew(this Image source, float degreesX, float degreesY, ProgressEventHandler progressHandler = null)
{ {
return Skew(source, degreesX, degreesY, Point.Empty, true, progressHandler); return Skew(source, degreesX, degreesY, true, progressHandler);
} }
/// <summary> /// <summary>
/// Skews an image by the given angles in degrees around the given center point. /// Skews an image by the given angles in degrees.
/// </summary> /// </summary>
/// <param name="source">The image to skew.</param> /// <param name="source">The image to skew.</param>
/// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param> /// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param> /// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param>
/// <param name="center">The center point at which to skew the image.</param>
/// <param name="expand">Whether to expand the image to fit the skewed result.</param> /// <param name="expand">Whether to expand the image to fit the skewed result.</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>
public static Image Skew(this Image source, float degreesX, float degreesY, Point center, bool expand, ProgressEventHandler progressHandler = null) public static Image Skew(this Image source, float degreesX, float degreesY, bool expand, ProgressEventHandler progressHandler = null)
{ {
SkewProcessor processor = new SkewProcessor { AngleX = degreesX, AngleY = degreesY, Center = center, Expand = expand }; SkewProcessor processor = new SkewProcessor { AngleX = degreesX, AngleY = degreesY, Expand = expand };
processor.OnProgress += progressHandler; processor.OnProgress += progressHandler;
try try

4
tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

@ -429,7 +429,7 @@ namespace ImageProcessorCore.Tests
Image image = new Image(stream); Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}")) using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}"))
{ {
image.Rotate(63, this.ProgressUpdate) image.Rotate(-170, this.ProgressUpdate)
.Save(output); .Save(output);
} }
} }
@ -454,7 +454,7 @@ namespace ImageProcessorCore.Tests
Image image = new Image(stream); Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"TestOutput/Skew/{filename}")) using (FileStream output = File.OpenWrite($"TestOutput/Skew/{filename}"))
{ {
image.Skew(-15, 12, this.ProgressUpdate) image.Skew(-20, -10, this.ProgressUpdate)
.Save(output); .Save(output);
} }
} }

Loading…
Cancel
Save