Browse Source

Merge pull request #904 from SixLabors/af/non-generic-image-baseclass

Introduce a non-generic Image base class
af/merge-core
Anton Firsov 7 years ago
committed by GitHub
parent
commit
86bd2b0889
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      ImageSharp.sln.DotSettings
  2. 2
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  3. 4
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  4. 3
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  5. 19
      src/ImageSharp/Formats/Bmp/ImageExtensions.cs
  6. 3
      src/ImageSharp/Formats/Gif/GifDecoder.cs
  7. 19
      src/ImageSharp/Formats/Gif/ImageExtensions.cs
  8. 13
      src/ImageSharp/Formats/IImageDecoder.cs
  9. 19
      src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
  10. 3
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  11. 8
      src/ImageSharp/Formats/PixelTypeInfo.cs
  12. 18
      src/ImageSharp/Formats/Png/ImageExtensions.cs
  13. 3
      src/ImageSharp/Formats/Png/PngDecoder.cs
  14. 22
      src/ImageSharp/IImageVisitor.cs
  15. 16
      src/ImageSharp/Image.Decode.cs
  16. 209
      src/ImageSharp/Image.FromBytes.cs
  17. 49
      src/ImageSharp/Image.FromFile.cs
  18. 72
      src/ImageSharp/Image.FromStream.cs
  19. 2
      src/ImageSharp/Image.LoadPixelData.cs
  20. 10
      src/ImageSharp/Image.WrapMemory.cs
  21. 123
      src/ImageSharp/Image.cs
  22. 12
      src/ImageSharp/ImageExtensions.cs
  23. 2
      src/ImageSharp/ImageSharp.csproj
  24. 1
      src/ImageSharp/ImageSharp.csproj.DotSettings
  25. 96
      src/ImageSharp/Image{TPixel}.cs
  26. 11
      src/ImageSharp/Processing/AutoOrientExtensions.cs
  27. 3
      src/ImageSharp/Processing/BackgroundColorExtensions.cs
  28. 11
      src/ImageSharp/Processing/BinaryDiffuseExtensions.cs
  29. 11
      src/ImageSharp/Processing/BinaryDitherExtensions.cs
  30. 11
      src/ImageSharp/Processing/BinaryThresholdExtensions.cs
  31. 19
      src/ImageSharp/Processing/BlackWhiteExtensions.cs
  32. 27
      src/ImageSharp/Processing/BoxBlurExtensions.cs
  33. 19
      src/ImageSharp/Processing/BrightnessExtensions.cs
  34. 39
      src/ImageSharp/Processing/ColorBlindnessExtensions.cs
  35. 20
      src/ImageSharp/Processing/ContrastExtensions.cs
  36. 20
      src/ImageSharp/Processing/CropExtensions.cs
  37. 12
      src/ImageSharp/Processing/DefaultInternalImageProcessorContext.cs
  38. 97
      src/ImageSharp/Processing/DetectEdgesExtensions.cs
  39. 15
      src/ImageSharp/Processing/DiffuseExtensions.cs
  40. 13
      src/ImageSharp/Processing/DitherExtensions.cs
  41. 20
      src/ImageSharp/Processing/EntropyCropExtensions.cs
  42. 19
      src/ImageSharp/Processing/FilterExtensions.cs
  43. 12
      src/ImageSharp/Processing/FlipExtensions.cs
  44. 27
      src/ImageSharp/Processing/GaussianBlurExtensions.cs
  45. 33
      src/ImageSharp/Processing/GaussianSharpenExtensions.cs
  46. 27
      src/ImageSharp/Processing/GlowExtensions.cs
  47. 63
      src/ImageSharp/Processing/GrayscaleExtensions.cs
  48. 50
      src/ImageSharp/Processing/HistogramEqualizationExtension.cs
  49. 19
      src/ImageSharp/Processing/HueExtensions.cs
  50. 42
      src/ImageSharp/Processing/IImageProcessingContext.cs
  51. 21
      src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs
  52. 19
      src/ImageSharp/Processing/InvertExtensions.cs
  53. 19
      src/ImageSharp/Processing/KodachromeExtensions.cs
  54. 19
      src/ImageSharp/Processing/LomographExtensions.cs
  55. 40
      src/ImageSharp/Processing/OilPaintExtensions.cs
  56. 19
      src/ImageSharp/Processing/OpacityExtensions.cs
  57. 11
      src/ImageSharp/Processing/PadExtensions.cs
  58. 30
      src/ImageSharp/Processing/PixelateExtensions.cs
  59. 19
      src/ImageSharp/Processing/PolaroidExtensions.cs
  60. 48
      src/ImageSharp/Processing/ProcessingExtensions.cs
  61. 53
      src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
  62. 63
      src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
  63. 3
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
  64. 0
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
  65. 93
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs
  66. 0
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  67. 7
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
  68. 56
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
  69. 37
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs
  70. 49
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs
  71. 80
      src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
  72. 48
      src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs
  73. 102
      src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
  74. 42
      src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs
  75. 28
      src/ImageSharp/Processing/Processors/Convolution/IEdgeDetectorProcessor.cs
  76. 22
      src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs
  77. 57
      src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs
  78. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs
  79. 18
      src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs
  80. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs
  81. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs
  82. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs
  83. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs
  84. 20
      src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs
  85. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs
  86. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs
  87. 40
      src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs
  88. 14
      src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs
  89. 20
      src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs
  90. 18
      src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs
  91. 20
      src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs
  92. 18
      src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs
  93. 38
      src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs
  94. 16
      src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs
  95. 27
      src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs
  96. 6
      src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs
  97. 119
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs
  98. 129
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
  99. 91
      src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs
  100. 111
      src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs

1
ImageSharp.sln.DotSettings

@ -388,4 +388,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

2
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -10,7 +10,9 @@
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
<LangVersion>7.3</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

4
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -18,11 +18,9 @@ namespace SixLabors.ImageSharp.Advanced
/// <summary>
/// Gets the configuration for the image.
/// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image.</param>
/// <returns>Returns the configuration.</returns>
public static Configuration GetConfiguration<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
public static Configuration GetConfiguration(this Image source)
=> GetConfiguration((IConfigurable)source);
/// <summary>

3
src/ImageSharp/Formats/Bmp/BmpDecoder.cs

@ -30,6 +30,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
return new BmpDecoderCore(configuration, this).Decode<TPixel>(stream);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{

19
src/ImageSharp/Formats/Bmp/ImageExtensions.cs

@ -2,38 +2,35 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Saves the image to the given stream with the bmp format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
=> source.SaveAsBmp(stream, null);
public static void SaveAsBmp(this Image source, Stream stream) => source.SaveAsBmp(stream, null);
/// <summary>
/// Saves the image to the given stream with the bmp format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream, BmpEncoder encoder)
where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance));
public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) =>
source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance));
}
}
}

3
src/ImageSharp/Formats/Gif/GifDecoder.cs

@ -44,5 +44,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
var decoder = new GifDecoderCore(configuration, this);
return decoder.Identify(stream);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
}
}

19
src/ImageSharp/Formats/Gif/ImageExtensions.cs

@ -2,38 +2,35 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Saves the image to the given stream in the gif format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
=> source.SaveAsGif(stream, null);
public static void SaveAsGif(this Image source, Stream stream) => source.SaveAsGif(stream, null);
/// <summary>
/// Saves the image to the given stream in the gif format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream, GifEncoder encoder)
where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance));
public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) =>
source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance));
}
}
}

13
src/ImageSharp/Formats/IImageDecoder.cs

@ -12,13 +12,22 @@ namespace SixLabors.ImageSharp.Formats
public interface IImageDecoder
{
/// <summary>
/// Decodes the image from the specified stream to the <see cref="ImageFrame{TPixel}"/>.
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The decoded image</returns>
/// <returns>The decoded image of a given pixel type.</returns>
Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>;
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/>.
/// The decoder is free to choose the pixel type.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The decoded image of a pixel type chosen by the decoder.</returns>
Image Decode(Configuration configuration, Stream stream);
}
}

19
src/ImageSharp/Formats/Jpeg/ImageExtensions.cs

@ -2,38 +2,35 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Saves the image to the given stream with the jpeg format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
=> SaveAsJpeg(source, stream, null);
public static void SaveAsJpeg(this Image source, Stream stream) => SaveAsJpeg(source, stream, null);
/// <summary>
/// Saves the image to the given stream with the jpeg format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream, JpegEncoder encoder)
where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance));
public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) =>
source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance));
}
}
}

3
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -38,5 +38,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return decoder.Identify(stream);
}
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
}
}

8
src/ImageSharp/Formats/PixelTypeInfo.cs

@ -1,6 +1,10 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats
{
/// <summary>
@ -21,5 +25,9 @@ namespace SixLabors.ImageSharp.Formats
/// Gets color depth, in number of bits per pixel.
/// </summary>
public int BitsPerPixel { get; }
internal static PixelTypeInfo Create<TPixel>()
where TPixel : struct, IPixel<TPixel> =>
new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
}
}

18
src/ImageSharp/Formats/Png/ImageExtensions.cs

@ -2,39 +2,35 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Saves the image to the given stream with the png format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
=> SaveAsPng(source, stream, null);
public static void SaveAsPng(this Image source, Stream stream) => SaveAsPng(source, stream, null);
/// <summary>
/// Saves the image to the given stream with the png format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, PngEncoder encoder)
where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance));
public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) =>
source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance));
}
}

3
src/ImageSharp/Formats/Png/PngDecoder.cs

@ -59,5 +59,8 @@ namespace SixLabors.ImageSharp.Formats.Png
var decoder = new PngDecoderCore(configuration, this);
return decoder.Identify(stream);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
}
}

22
src/ImageSharp/IImageVisitor.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// A visitor to implement double-dispatch pattern in order to apply pixel-specific operations
/// on non-generic <see cref="Image"/> instances. The operation is dispatched by <see cref="Image.AcceptVisitor"/>.
/// </summary>
internal interface IImageVisitor
{
/// <summary>
/// Provides a pixel-specific implementation for a given operation.
/// </summary>
/// <param name="image">The image.</param>
/// <typeparam name="TPixel">The pixel type.</typeparam>
void Visit<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>;
}
}

16
src/ImageSharp/Image.Decode.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the decoding of new images.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// Creates an <see cref="Image{TPixel}"/> instance backed by an uninitialized memory buffer.
@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp
/// The image might be filled with memory garbage.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="configuration">The <see cref="Configuration"/></param>
/// <param name="configuration">The <see cref="ImageSharp.Configuration"/></param>
/// <param name="width">The width of the image</param>
/// <param name="height">The height of the image</param>
/// <param name="metadata">The <see cref="ImageMetadata"/></param>
@ -103,6 +103,18 @@ namespace SixLabors.ImageSharp
return (img, format);
}
private static (Image img, IImageFormat format) Decode(Stream stream, Configuration config)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
if (decoder is null)
{
return (null, null);
}
Image img = decoder.Decode(config, stream);
return (img, format);
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>

209
src/ImageSharp/Image.FromBytes.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from a byte array.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided byte array this calculates the images format.
@ -44,48 +44,6 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data) => Load<Rgba32>(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, out IImageFormat format) => Load<Rgba32>(Configuration.Default, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data) => Load<Rgba32>(config, data);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data, out IImageFormat format) => Load<Rgba32>(config, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, IImageDecoder decoder) => Load<Rgba32>(data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data, IImageDecoder decoder) => Load<Rgba32>(config, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
@ -117,9 +75,9 @@ namespace SixLabors.ImageSharp
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data)
where TPixel : struct, IPixel<TPixel>
{
using (var steram = new MemoryStream(data))
using (var stream = new MemoryStream(data))
{
return Load<TPixel>(config, steram);
return Load<TPixel>(config, stream);
}
}
@ -211,29 +169,36 @@ namespace SixLabors.ImageSharp
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte span.
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(ReadOnlySpan<byte> data) => Load<Rgba32>(Configuration.Default, data);
/// <param name="data">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data)
where TPixel : struct, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte span.
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte span containing encoded image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, ReadOnlySpan<byte> data) => Load<Rgba32>(config, data);
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data, out IImageFormat format)
where TPixel : struct, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte span containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data)
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data, IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data);
=> Load<TPixel>(Configuration.Default, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
@ -299,5 +264,135 @@ namespace SixLabors.ImageSharp
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The detected format.</param>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(byte[] data, out IImageFormat format) =>
Load(Configuration.Default, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(byte[] data, IImageDecoder decoder) => Load(Configuration.Default, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image Load(Configuration config, byte[] data) => Load(config, data, out _);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image Load(Configuration config, byte[] data, IImageDecoder decoder)
{
using (var stream = new MemoryStream(data))
{
return Load(config, stream, decoder);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image Load(Configuration config, byte[] data, out IImageFormat format)
{
using (var stream = new MemoryStream(data))
{
return Load(config, stream, out format);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data) => Load(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, IImageDecoder decoder) =>
Load(Configuration.Default, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The detected format.</param>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, out IImageFormat format) =>
Load(Configuration.Default, data, out format);
/// <summary>
/// Decodes a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <returns>A new <see cref="Image"/>.</returns>
public static unsafe Image Load(Configuration config, ReadOnlySpan<byte> data) => Load(config, data, out _);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image"/>.</returns>
public static unsafe Image Load(
Configuration config,
ReadOnlySpan<byte> data,
IImageDecoder decoder)
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load(config, stream, decoder);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>>
/// <returns>A new <see cref="Image"/>.</returns>
public static unsafe Image Load(
Configuration config,
ReadOnlySpan<byte> data,
out IImageFormat format)
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load(config, stream, out format);
}
}
}
}
}

49
src/ImageSharp/Image.FromFile.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from a given file.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided file this calculates the images mime type.
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path) => Load<Rgba32>(path);
public static Image Load(string path) => Load(Configuration.Default, path);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, out IImageFormat format) => Load<Rgba32>(path, out format);
public static Image Load(string path, out IImageFormat format) => Load(Configuration.Default, path, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
@ -68,19 +68,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path) => Load<Rgba32>(config, path);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path, out IImageFormat format) => Load<Rgba32>(config, path, out format);
public static Image Load(Configuration config, string path) => Load(config, path, out _);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
@ -92,7 +80,13 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path, IImageDecoder decoder) => Load<Rgba32>(config, path, decoder);
public static Image Load(Configuration config, string path, IImageDecoder decoder)
{
using (Stream stream = config.FileSystem.OpenRead(path))
{
return Load(config, stream, decoder);
}
}
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
@ -103,7 +97,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, IImageDecoder decoder) => Load<Rgba32>(path, decoder);
public static Image Load(string path, IImageDecoder decoder) => Load(Configuration.Default, path, decoder);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
@ -175,6 +169,25 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// The pixel type is selected by the decoder.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(Configuration config, string path, out IImageFormat format)
{
using (Stream stream = config.FileSystem.OpenRead(path))
{
return Load(config, stream, out format);
}
}
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>

72
src/ImageSharp/Image.FromStream.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from a given stream.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided stream this calculates the images mime type.
@ -56,50 +56,54 @@ namespace SixLabors.ImageSharp
=> WithSeekableStream(config, stream, s => InternalIdentity(s, config ?? Configuration.Default));
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, out IImageFormat format) => Load<Rgba32>(stream, out format);
/// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Stream stream, out IImageFormat format) => Load(Configuration.Default, stream, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream) => Load<Rgba32>(stream);
/// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Stream stream) => Load(Configuration.Default, stream);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, IImageDecoder decoder) => Load<Rgba32>(stream, decoder);
/// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Stream stream, IImageDecoder decoder) => Load(Configuration.Default, stream, decoder);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Configuration config, Stream stream) => Load<Rgba32>(config, stream);
/// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) =>
WithSeekableStream(config, stream, s => decoder.Decode(config, s));
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Configuration config, Stream stream, out IImageFormat format)
=> Load<Rgba32>(config, stream, out format);
/// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Configuration config, Stream stream) => Load(config, stream, out _);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -194,6 +198,38 @@ namespace SixLabors.ImageSharp
throw new NotSupportedException(sb.ToString());
}
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(Configuration config, Stream stream, out IImageFormat format)
{
config = config ?? Configuration.Default;
(Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config));
format = data.format;
if (data.img != null)
{
return data.img;
}
var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in config.ImageFormatsManager.ImageDecoders)
{
sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
}
throw new NotSupportedException(sb.ToString());
}
private static T WithSeekableStream<T>(Configuration config, Stream stream, Func<Stream, T> action)
{
if (!stream.CanRead)

2
src/ImageSharp/Image.LoadPixelData.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from raw pixel data.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.

10
src/ImageSharp/Image.WrapMemory.cs

@ -13,14 +13,14 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing wrapping an existing memory area as an image.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="config">The <see cref="Configuration"/></param>
/// <param name="config">The <see cref="ImageSharp.Configuration"/></param>
/// <param name="pixelMemory">The pixel memory.</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>
@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp
/// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="config">The <see cref="Configuration"/></param>
/// <param name="config">The <see cref="ImageSharp.Configuration"/></param>
/// <param name="pixelMemory">The pixel memory.</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp
/// It will be disposed together with the result image.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="config">The <see cref="Configuration"/></param>
/// <param name="config">The <see cref="ImageSharp.Configuration"/></param>
/// <param name="pixelMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>
@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp
/// It will be disposed together with the result image.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="config">The <see cref="Configuration"/></param>
/// <param name="config">The <see cref="ImageSharp.Configuration"/></param>
/// <param name="pixelMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image.</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>

123
src/ImageSharp/Image.cs

@ -0,0 +1,123 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// For the non-generic <see cref="Image"/> type, the pixel type is only known at runtime.
/// <see cref="Image"/> is always implemented by a pixel-specific <see cref="Image{TPixel}"/> instance.
/// </summary>
public abstract partial class Image : IImage, IConfigurable
{
private Size size;
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/>.</param>
/// <param name="pixelType">The <see cref="PixelTypeInfo"/>.</param>
/// <param name="metadata">The <see cref="ImageMetadata"/>.</param>
/// <param name="size">The <see cref="size"/>.</param>
protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata metadata, Size size)
{
this.Configuration = configuration ?? Configuration.Default;
this.PixelType = pixelType;
this.size = size;
this.Metadata = metadata ?? new ImageMetadata();
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
internal Image(
Configuration configuration,
PixelTypeInfo pixelType,
ImageMetadata metadata,
int width,
int height)
: this(configuration, pixelType, metadata, new Size(width, height))
{
}
/// <summary>
/// Gets the <see cref="Configuration"/>.
/// </summary>
protected Configuration Configuration { get; }
/// <inheritdoc/>
public PixelTypeInfo PixelType { get; }
/// <inheritdoc />
public int Width => this.size.Width;
/// <inheritdoc />
public int Height => this.size.Height;
/// <inheritdoc/>
public ImageMetadata Metadata { get; }
/// <summary>
/// Gets the pixel buffer.
/// </summary>
Configuration IConfigurable.Configuration => this.Configuration;
/// <inheritdoc />
public abstract void Dispose();
/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream or encoder is null.</exception>
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));
EncodeVisitor visitor = new EncodeVisitor(encoder, stream);
this.AcceptVisitor(visitor);
}
/// <summary>
/// Accept a <see cref="IImageVisitor"/>.
/// Implemented by <see cref="Image{TPixel}"/> invoking <see cref="IImageVisitor.Visit{TPixel}"/>
/// with the pixel type of the image.
/// </summary>
internal abstract void AcceptVisitor(IImageVisitor visitor);
/// <summary>
/// Update the size of the image after mutation.
/// </summary>
/// <param name="size">The <see cref="Size"/>.</param>
protected void UpdateSize(Size size) => this.size = size;
private class EncodeVisitor : IImageVisitor
{
private readonly IImageEncoder encoder;
private readonly Stream stream;
public EncodeVisitor(IImageEncoder encoder, Stream stream)
{
this.encoder = encoder;
this.stream = stream;
}
public void Visit<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
this.encoder.Encode(image, this.stream);
}
}
}
}

12
src/ImageSharp/ImageExtensions.cs

@ -19,12 +19,10 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The source image.</param>
/// <param name="filePath">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, string filePath)
where TPixel : struct, IPixel<TPixel>
public static void Save(this Image source, string filePath)
{
Guard.NotNullOrWhiteSpace(filePath, nameof(filePath));
@ -62,13 +60,11 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The source image.</param>
/// <param name="filePath">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="ArgumentNullException">Thrown if the encoder is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, string filePath, IImageEncoder encoder)
where TPixel : struct, IPixel<TPixel>
public static void Save(this Image source, string filePath, IImageEncoder encoder)
{
Guard.NotNull(encoder, nameof(encoder));
using (Stream fs = source.GetConfiguration().FileSystem.Create(filePath))
@ -80,13 +76,11 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image in.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, Stream stream, IImageFormat format)
where TPixel : struct, IPixel<TPixel>
public static void Save(this Image source, Stream stream, IImageFormat format)
{
Guard.NotNull(format, nameof(format));
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);

2
src/ImageSharp/ImageSharp.csproj

@ -10,7 +10,9 @@
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0;net472</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp</AssemblyName>

1
src/ImageSharp/ImageSharp.csproj.DotSettings

@ -6,5 +6,6 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixelimplementations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixeltypes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cutils/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Cconvolution_005Ckernels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresamplers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresize/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

96
src/ImageSharp/Image{TPixel}.cs

@ -3,26 +3,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// For generic <see cref="Image{TPixel}"/>-s the pixel type is known at compile time.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed class Image<TPixel> : IImage, IConfigurable
public sealed class Image<TPixel> : Image
where TPixel : struct, IPixel<TPixel>
{
private readonly Configuration configuration;
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
@ -68,16 +66,14 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, ImageMetadata metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height)
{
this.configuration = configuration ?? Configuration.Default;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.Metadata = metadata ?? new ImageMetadata();
this.Frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// wrapping an external <see cref="MemorySource{T}"/>
/// wrapping an external <see cref="MemorySource{T}"/>.
/// </summary>
/// <param name="configuration">The configuration providing initialization code which allows extending the library.</param>
/// <param name="memorySource">The memory source.</param>
@ -85,10 +81,8 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, MemorySource<TPixel> memorySource, int width, int height, ImageMetadata metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height)
{
this.configuration = configuration;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.Metadata = metadata;
this.Frames = new ImageFrameCollection<TPixel>(this, width, height, memorySource);
}
@ -102,10 +96,8 @@ namespace SixLabors.ImageSharp
/// <param name="backgroundColor">The color to initialize the pixels with.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, TPixel backgroundColor, ImageMetadata metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height)
{
this.configuration = configuration ?? Configuration.Default;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.Metadata = metadata ?? new ImageMetadata();
this.Frames = new ImageFrameCollection<TPixel>(this, width, height, backgroundColor);
}
@ -117,31 +109,11 @@ namespace SixLabors.ImageSharp
/// <param name="metadata">The images metadata.</param>
/// <param name="frames">The frames that will be owned by this image instance.</param>
internal Image(Configuration configuration, ImageMetadata metadata, IEnumerable<ImageFrame<TPixel>> frames)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, ValidateFramesAndGetSize(frames))
{
this.configuration = configuration ?? Configuration.Default;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.Metadata = metadata ?? new ImageMetadata();
this.Frames = new ImageFrameCollection<TPixel>(this, frames);
}
/// <summary>
/// Gets the pixel buffer.
/// </summary>
Configuration IConfigurable.Configuration => this.configuration;
/// <inheritdoc/>
public PixelTypeInfo PixelType { get; }
/// <inheritdoc/>
public int Width => this.Frames.RootFrame.Width;
/// <inheritdoc/>
public int Height => this.Frames.RootFrame.Height;
/// <inheritdoc/>
public ImageMetadata Metadata { get; }
/// <summary>
/// Gets the frames.
/// </summary>
@ -161,29 +133,14 @@ namespace SixLabors.ImageSharp
public TPixel this[int x, int y]
{
get => this.PixelSource.PixelBuffer[x, y];
set => this.PixelSource.PixelBuffer[x, y] = value;
}
/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream or encoder is null.</exception>
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));
encoder.Encode(this, stream);
}
/// <summary>
/// Clones the current image
/// </summary>
/// <returns>Returns a new image with all the same metadata as the original.</returns>
public Image<TPixel> Clone() => this.Clone(this.configuration);
public Image<TPixel> Clone() => this.Clone(this.Configuration);
/// <summary>
/// Clones the current image with the given configuration.
@ -202,14 +159,14 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <returns>The <see cref="Image{TPixel2}"/></returns>
public Image<TPixel2> CloneAs<TPixel2>()
where TPixel2 : struct, IPixel<TPixel2> => this.CloneAs<TPixel2>(this.configuration);
where TPixel2 : struct, IPixel<TPixel2> => this.CloneAs<TPixel2>(this.Configuration);
/// <summary>
/// Returns a copy of the image in the given pixel format.
/// </summary>
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <param name="configuration">The configuration providing initialization code which allows extending the library.</param>
/// <returns>The <see cref="Image{TPixel2}"/></returns>
/// <returns>The <see cref="Image{TPixel2}"/>.</returns>
public Image<TPixel2> CloneAs<TPixel2>(Configuration configuration)
where TPixel2 : struct, IPixel<TPixel2>
{
@ -218,7 +175,13 @@ namespace SixLabors.ImageSharp
}
/// <inheritdoc/>
public void Dispose() => this.Frames.Dispose();
public override void Dispose() => this.Frames.Dispose();
/// <inheritdoc />
internal override void AcceptVisitor(IImageVisitor visitor)
{
visitor.Visit(this);
}
/// <inheritdoc/>
public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}";
@ -235,6 +198,29 @@ namespace SixLabors.ImageSharp
{
this.Frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.Frames[i]);
}
this.UpdateSize(pixelSource.Size());
}
private static Size ValidateFramesAndGetSize(IEnumerable<ImageFrame<TPixel>> frames)
{
Guard.NotNull(frames, nameof(frames));
ImageFrame<TPixel> rootFrame = frames.FirstOrDefault();
if (rootFrame == null)
{
throw new ArgumentException("Must not be empty.", nameof(frames));
}
Size rootSize = rootFrame.Size();
if (frames.Any(f => f.Size() != rootSize))
{
throw new ArgumentException("The provided frames must be of the same size.", nameof(frames));
}
return rootSize;
}
}
}

11
src/ImageSharp/Processing/AutoOrientExtensions.cs

@ -7,18 +7,17 @@ using SixLabors.ImageSharp.Processing.Processors.Transforms;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of auto-orientation operations to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of auto-orientation operations to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class AutoOrientExtensions
{
/// <summary>
/// Adjusts an image so that its orientation is suitable for viewing. Adjustments are based on EXIF metadata embedded in the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> AutoOrient<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new AutoOrientProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext AutoOrient(this IImageProcessingContext source)
=> source.ApplyProcessor(new AutoOrientProcessor());
}
}

3
src/ImageSharp/Processing/BackgroundColorExtensions.cs

@ -8,7 +8,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of a background color to the <see cref="Image{TPixel}"/> type.
/// Defines extension methods to replace the background color of an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BackgroundColorExtensions
{

11
src/ImageSharp/Processing/BinaryDiffuseExtensions.cs

@ -9,7 +9,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds binary diffusion extensions to the <see cref="Image{TPixel}"/> type.
/// Defines extension methods to apply binary diffusion on an <see cref="Image{TPixel}"/>
/// using Mutate/Clone.
/// </summary>
public static class BinaryDiffuseExtensions
{
@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold));
@ -35,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold), rectangle);
@ -49,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold, upperColor, lowerColor));
@ -66,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold, upperColor, lowerColor), rectangle);

11
src/ImageSharp/Processing/BinaryDitherExtensions.cs

@ -9,7 +9,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds binary dithering extensions to the <see cref="Image{TPixel}"/> type.
/// Defines extensions to apply binary dithering on an <see cref="Image{TPixel}"/>
/// using Mutate/Clone.
/// </summary>
public static class BinaryDitherExtensions
{
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither));
@ -32,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="dither">The ordered ditherer.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel upperColor, TPixel lowerColor)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither, upperColor, lowerColor));
@ -46,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither), rectangle);
@ -62,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel upperColor, TPixel lowerColor, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither, upperColor, lowerColor), rectangle);

11
src/ImageSharp/Processing/BinaryThresholdExtensions.cs

@ -8,7 +8,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds binary thresholding extensions to the <see cref="Image{TPixel}"/> type.
/// Defines extension methods to apply binary thresholding on an <see cref="Image{TPixel}"/>
/// using Mutate/Clone.
/// </summary>
public static class BinaryThresholdExtensions
{
@ -18,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold));
@ -32,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold), rectangle);
@ -45,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, TPixel upperColor, TPixel lowerColor)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold, upperColor, lowerColor));
@ -61,7 +62,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, TPixel upperColor, TPixel lowerColor, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold, upperColor, lowerColor), rectangle);

19
src/ImageSharp/Processing/BlackWhiteExtensions.cs

@ -8,31 +8,28 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of black and white toning to the <see cref="Image{TPixel}"/> type.
/// Defines extension methods that allow the application of black and white toning to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BlackWhiteExtensions
{
/// <summary>
/// Applies black and white toning to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BlackWhite<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BlackWhiteProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BlackWhite(this IImageProcessingContext source)
=> source.ApplyProcessor(new BlackWhiteProcessor());
/// <summary>
/// Applies black and white toning to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BlackWhite<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BlackWhiteProcessor<TPixel>(), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BlackWhite(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new BlackWhiteProcessor(), rectangle);
}
}

27
src/ImageSharp/Processing/BoxBlurExtensions.cs

@ -8,43 +8,38 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds box blurring extensions to the <see cref="Image{TPixel}"/> type.
/// Defines extensions methods to apply box blurring to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BoxBlurExtensions
{
/// <summary>
/// Applies a box blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BoxBlur<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BoxBlurProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BoxBlur(this IImageProcessingContext source)
=> source.ApplyProcessor(new BoxBlurProcessor());
/// <summary>
/// Applies a box blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BoxBlur<TPixel>(this IImageProcessingContext<TPixel> source, int radius)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BoxBlurProcessor<TPixel>(radius));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BoxBlur(this IImageProcessingContext source, int radius)
=> source.ApplyProcessor(new BoxBlurProcessor(radius));
/// <summary>
/// Applies a box blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BoxBlur<TPixel>(this IImageProcessingContext<TPixel> source, int radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BoxBlurProcessor<TPixel>(radius), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BoxBlur(this IImageProcessingContext source, int radius, Rectangle rectangle)
=> source.ApplyProcessor(new BoxBlurProcessor(radius), rectangle);
}
}

19
src/ImageSharp/Processing/BrightnessExtensions.cs

@ -8,7 +8,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the alteration of the brightness component to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the alteration of the brightness component of an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BrightnessExtensions
{
@ -19,13 +20,11 @@ namespace SixLabors.ImageSharp.Processing
/// A value of 0 will create an image that is completely black. A value of 1 leaves the input unchanged.
/// Other values are linear multipliers on the effect. Values of an amount over 1 are allowed, providing brighter results.
/// </remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Brightness<TPixel>(this IImageProcessingContext<TPixel> source, float amount)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BrightnessProcessor<TPixel>(amount));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Brightness(this IImageProcessingContext source, float amount)
=> source.ApplyProcessor(new BrightnessProcessor(amount));
/// <summary>
/// Alters the brightness component of the image.
@ -34,15 +33,13 @@ namespace SixLabors.ImageSharp.Processing
/// A value of 0 will create an image that is completely black. A value of 1 leaves the input unchanged.
/// Other values are linear multipliers on the effect. Values of an amount over 1 are allowed, providing brighter results.
/// </remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Brightness<TPixel>(this IImageProcessingContext<TPixel> source, float amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BrightnessProcessor<TPixel>(amount), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Brightness(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new BrightnessProcessor(amount), rectangle);
}
}

39
src/ImageSharp/Processing/ColorBlindnessExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Filters;
using SixLabors.Primitives;
@ -9,56 +8,52 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that simulate the effects of various color blindness disorders to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that simulate the effects of various color blindness disorders on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class ColorBlindnessExtensions
{
/// <summary>
/// Applies the given colorblindness simulator to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindnessMode colorBlindness)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(GetProcessor<TPixel>(colorBlindness));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext ColorBlindness(this IImageProcessingContext source, ColorBlindnessMode colorBlindness)
=> source.ApplyProcessor(GetProcessor(colorBlindness));
/// <summary>
/// Applies the given colorblindness simulator to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="colorBlindnessMode">The type of color blindness simulator to apply.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindnessMode colorBlindnessMode, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(GetProcessor<TPixel>(colorBlindnessMode), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext ColorBlindness(this IImageProcessingContext source, ColorBlindnessMode colorBlindnessMode, Rectangle rectangle)
=> source.ApplyProcessor(GetProcessor(colorBlindnessMode), rectangle);
private static IImageProcessor<TPixel> GetProcessor<TPixel>(ColorBlindnessMode colorBlindness)
where TPixel : struct, IPixel<TPixel>
private static IImageProcessor GetProcessor(ColorBlindnessMode colorBlindness)
{
switch (colorBlindness)
{
case ColorBlindnessMode.Achromatomaly:
return new AchromatomalyProcessor<TPixel>();
return new AchromatomalyProcessor();
case ColorBlindnessMode.Achromatopsia:
return new AchromatopsiaProcessor<TPixel>();
return new AchromatopsiaProcessor();
case ColorBlindnessMode.Deuteranomaly:
return new DeuteranomalyProcessor<TPixel>();
return new DeuteranomalyProcessor();
case ColorBlindnessMode.Deuteranopia:
return new DeuteranopiaProcessor<TPixel>();
return new DeuteranopiaProcessor();
case ColorBlindnessMode.Protanomaly:
return new ProtanomalyProcessor<TPixel>();
return new ProtanomalyProcessor();
case ColorBlindnessMode.Protanopia:
return new ProtanopiaProcessor<TPixel>();
return new ProtanopiaProcessor();
case ColorBlindnessMode.Tritanomaly:
return new TritanomalyProcessor<TPixel>();
return new TritanomalyProcessor();
default:
return new TritanopiaProcessor<TPixel>();
return new TritanopiaProcessor();
}
}
}

20
src/ImageSharp/Processing/ContrastExtensions.cs

@ -1,14 +1,14 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Filters;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the alteration of the contrast component to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the alteration of the contrast component of an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class ContrastExtensions
{
@ -19,13 +19,11 @@ namespace SixLabors.ImageSharp.Processing
/// A value of 0 will create an image that is completely gray. A value of 1 leaves the input unchanged.
/// Other values are linear multipliers on the effect. Values of an amount over 1 are allowed, providing results with more contrast.
/// </remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Contrast<TPixel>(this IImageProcessingContext<TPixel> source, float amount)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ContrastProcessor<TPixel>(amount));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Contrast(this IImageProcessingContext source, float amount)
=> source.ApplyProcessor(new ContrastProcessor(amount));
/// <summary>
/// Alters the contrast component of the image.
@ -34,15 +32,13 @@ namespace SixLabors.ImageSharp.Processing
/// A value of 0 will create an image that is completely gray. A value of 1 leaves the input unchanged.
/// Other values are linear multipliers on the effect. Values of an amount over 1 are allowed, providing results with more contrast.
/// </remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Contrast<TPixel>(this IImageProcessingContext<TPixel> source, float amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ContrastProcessor<TPixel>(amount), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Contrast(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new ContrastProcessor(amount), rectangle);
}
}

20
src/ImageSharp/Processing/CropExtensions.cs

@ -1,40 +1,36 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of cropping operations to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of cropping operations on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class CropExtensions
{
/// <summary>
/// Crops an image to the given width and height.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to resize.</param>
/// <param name="width">The target image width.</param>
/// <param name="height">The target image height.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Crop<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height)
where TPixel : struct, IPixel<TPixel>
=> Crop(source, new Rectangle(0, 0, width, height));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Crop(this IImageProcessingContext source, int width, int height) =>
Crop(source, new Rectangle(0, 0, width, height));
/// <summary>
/// Crops an image to the given rectangle.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to crop.</param>
/// <param name="cropRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to retain.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Crop<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle cropRectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new CropProcessor<TPixel>(cropRectangle, source.GetCurrentSize()));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Crop(this IImageProcessingContext source, Rectangle cropRectangle) =>
source.ApplyProcessor(new CropProcessor(cropRectangle, source.GetCurrentSize()));
}
}

12
src/ImageSharp/Processing/DefaultInternalImageProcessorContext.cs

@ -53,6 +53,18 @@ namespace SixLabors.ImageSharp.Processing
/// <inheritdoc/>
public Size GetCurrentSize() => this.GetCurrentBounds().Size;
public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
{
var processorImplementation = processor.CreatePixelSpecificProcessor<TPixel>();
return this.ApplyProcessor(processorImplementation, rectangle);
}
public IImageProcessingContext ApplyProcessor(IImageProcessor processor)
{
var processorImplementation = processor.CreatePixelSpecificProcessor<TPixel>();
return this.ApplyProcessor(processorImplementation);
}
/// <inheritdoc/>
public IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle)
{

97
src/ImageSharp/Processing/DetectEdgesExtensions.cs

@ -1,89 +1,86 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Convolution;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds edge detection extensions to the <see cref="Image{TPixel}"/> type.
/// Defines edge detection extensions applicable on an <see cref="Image"/> using Mutate/Clone.
/// </summary>
public static class DetectEdgesExtensions
{
/// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor{TPixel}"/> filter
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter
/// operating in grayscale mode.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, new SobelProcessor<TPixel>(true));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(this IImageProcessingContext source) =>
DetectEdges(source, new SobelProcessor(true));
/// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor{TPixel}"/> filter
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter
/// operating in grayscale mode.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, rectangle, new SobelProcessor<TPixel>(true));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(this IImageProcessingContext source, Rectangle rectangle) =>
DetectEdges(source, rectangle, new SobelProcessor(true));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetectionOperators filter)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, GetProcessor<TPixel>(filter, true));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectionOperators filter) =>
DetectEdges(source, GetProcessor(filter, true));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="grayscale">Whether to convert the image to grayscale first. Defaults to true.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetectionOperators filter, bool grayscale)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, GetProcessor<TPixel>(filter, grayscale));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectionOperators filter,
bool grayscale) =>
DetectEdges(source, GetProcessor(filter, grayscale));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="grayscale">Whether to convert the image to grayscale first. Defaults to true.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetectionOperators filter, Rectangle rectangle, bool grayscale = true)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, rectangle, GetProcessor<TPixel>(filter, grayscale));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectionOperators filter,
Rectangle rectangle,
bool grayscale = true) =>
DetectEdges(source, rectangle, GetProcessor(filter, grayscale));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, IEdgeDetectorProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext DetectEdges(this IImageProcessingContext source, IImageProcessor filter)
{
return source.ApplyProcessor(filter);
}
@ -91,65 +88,65 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, IEdgeDetectorProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
Rectangle rectangle,
IImageProcessor filter)
{
source.ApplyProcessor(filter, rectangle);
return source;
}
private static IEdgeDetectorProcessor<TPixel> GetProcessor<TPixel>(EdgeDetectionOperators filter, bool grayscale)
where TPixel : struct, IPixel<TPixel>
private static IImageProcessor GetProcessor(EdgeDetectionOperators filter, bool grayscale)
{
IEdgeDetectorProcessor<TPixel> processor;
IImageProcessor processor;
switch (filter)
{
case EdgeDetectionOperators.Kayyali:
processor = new KayyaliProcessor<TPixel>(grayscale);
processor = new KayyaliProcessor(grayscale);
break;
case EdgeDetectionOperators.Kirsch:
processor = new KirschProcessor<TPixel>(grayscale);
processor = new KirschProcessor(grayscale);
break;
case EdgeDetectionOperators.Laplacian3x3:
processor = new Laplacian3x3Processor<TPixel>(grayscale);
processor = new Laplacian3x3Processor(grayscale);
break;
case EdgeDetectionOperators.Laplacian5x5:
processor = new Laplacian5x5Processor<TPixel>(grayscale);
processor = new Laplacian5x5Processor(grayscale);
break;
case EdgeDetectionOperators.LaplacianOfGaussian:
processor = new LaplacianOfGaussianProcessor<TPixel>(grayscale);
processor = new LaplacianOfGaussianProcessor(grayscale);
break;
case EdgeDetectionOperators.Prewitt:
processor = new PrewittProcessor<TPixel>(grayscale);
processor = new PrewittProcessor(grayscale);
break;
case EdgeDetectionOperators.RobertsCross:
processor = new RobertsCrossProcessor<TPixel>(grayscale);
processor = new RobertsCrossProcessor(grayscale);
break;
case EdgeDetectionOperators.Robinson:
processor = new RobinsonProcessor<TPixel>(grayscale);
processor = new RobinsonProcessor(grayscale);
break;
case EdgeDetectionOperators.Scharr:
processor = new ScharrProcessor<TPixel>(grayscale);
processor = new ScharrProcessor(grayscale);
break;
default:
processor = new SobelProcessor<TPixel>(grayscale);
processor = new SobelProcessor(grayscale);
break;
}

15
src/ImageSharp/Processing/DiffuseExtensions.cs

@ -8,7 +8,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Dithering
{
/// <summary>
/// Adds diffusion extensions to the <see cref="Image{TPixel}"/> type.
/// Defines extension methods to apply diffusion to an <see cref="Image{TPixel}"/>
/// using Mutate/Clone.
/// </summary>
public static class DiffuseExtensions
{
@ -17,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Diffuse(source, KnownDiffusers.FloydSteinberg, .5F);
@ -28,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel>
=> Diffuse(source, KnownDiffusers.FloydSteinberg, threshold);
@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold));
@ -55,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold), rectangle);
@ -68,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel[] palette)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold, palette));
@ -84,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel[] palette, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold, palette), rectangle);

13
src/ImageSharp/Processing/DitherExtensions.cs

@ -8,7 +8,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds dithering extensions to the <see cref="Image{TPixel}"/> type.
/// Defines dithering extensions to apply on an <see cref="Image{TPixel}"/>
/// using Mutate/Clone.
/// </summary>
public static class DitherExtensions
{
@ -17,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Dither(source, KnownDitherers.BayerDither4x4);
@ -28,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither));
@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel[] palette)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither, palette));
@ -54,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither), rectangle);
@ -69,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel[] palette, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither, palette), rectangle);

20
src/ImageSharp/Processing/EntropyCropExtensions.cs

@ -1,35 +1,31 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of entropy cropping operations to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of entropy cropping operations on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class EntropyCropExtensions
{
/// <summary>
/// Crops an image to the area of greatest entropy using a threshold for entropic density of <value>.5F</value>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to crop.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> EntropyCrop<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new EntropyCropProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext EntropyCrop(this IImageProcessingContext source) =>
source.ApplyProcessor(new EntropyCropProcessor());
/// <summary>
/// Crops an image to the area of greatest entropy.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to crop.</param>
/// <param name="threshold">The threshold for entropic density.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> EntropyCrop<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new EntropyCropProcessor<TPixel>(threshold));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext EntropyCrop(this IImageProcessingContext source, float threshold) =>
source.ApplyProcessor(new EntropyCropProcessor(threshold));
}
}

19
src/ImageSharp/Processing/FilterExtensions.cs

@ -9,33 +9,30 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of composable filters to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of composable filters to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class FilterExtensions
{
/// <summary>
/// Filters an image but the given color matrix
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="matrix">The filter color matrix</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Filter<TPixel>(this IImageProcessingContext<TPixel> source, ColorMatrix matrix)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new FilterProcessor<TPixel>(matrix));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Filter(this IImageProcessingContext source, ColorMatrix matrix)
=> source.ApplyProcessor(new FilterProcessor(matrix));
/// <summary>
/// Filters an image but the given color matrix
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="matrix">The filter color matrix</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Filter<TPixel>(this IImageProcessingContext<TPixel> source, ColorMatrix matrix, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new FilterProcessor<TPixel>(matrix), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Filter(this IImageProcessingContext source, ColorMatrix matrix, Rectangle rectangle)
=> source.ApplyProcessor(new FilterProcessor(matrix), rectangle);
}
}

12
src/ImageSharp/Processing/FlipExtensions.cs

@ -1,25 +1,23 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of flipping operations to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of flipping operations on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class FlipExtensions
{
/// <summary>
/// Flips an image by the given instructions.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="flipMode">The <see cref="FlipMode"/> to perform the flip.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Flip<TPixel>(this IImageProcessingContext<TPixel> source, FlipMode flipMode)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new FlipProcessor<TPixel>(flipMode));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Flip(this IImageProcessingContext source, FlipMode flipMode)
=> source.ApplyProcessor(new FlipProcessor(flipMode));
}
}

27
src/ImageSharp/Processing/GaussianBlurExtensions.cs

@ -8,43 +8,38 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds Gaussian blurring extensions to the <see cref="Image{TPixel}"/> type.
/// Defines Gaussian blurring extensions to apply on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class GaussianBlurExtensions
{
/// <summary>
/// Applies a Gaussian blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianBlur<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianBlurProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext GaussianBlur(this IImageProcessingContext source)
=> source.ApplyProcessor(new GaussianBlurProcessor());
/// <summary>
/// Applies a Gaussian blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianBlur<TPixel>(this IImageProcessingContext<TPixel> source, float sigma)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianBlurProcessor<TPixel>(sigma));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext GaussianBlur(this IImageProcessingContext source, float sigma)
=> source.ApplyProcessor(new GaussianBlurProcessor(sigma));
/// <summary>
/// Applies a Gaussian blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianBlur<TPixel>(this IImageProcessingContext<TPixel> source, float sigma, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianBlurProcessor<TPixel>(sigma), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext GaussianBlur(this IImageProcessingContext source, float sigma, Rectangle rectangle)
=> source.ApplyProcessor(new GaussianBlurProcessor(sigma), rectangle);
}
}

33
src/ImageSharp/Processing/GaussianSharpenExtensions.cs

@ -1,50 +1,47 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Convolution;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds Gaussian sharpening extensions to the <see cref="Image{TPixel}"/> type.
/// Defines Gaussian sharpening extensions to apply on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class GaussianSharpenExtensions
{
/// <summary>
/// Applies a Gaussian sharpening filter to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext GaussianSharpen(this IImageProcessingContext source) =>
source.ApplyProcessor(new GaussianSharpenProcessor());
/// <summary>
/// Applies a Gaussian sharpening filter to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source, float sigma)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext GaussianSharpen(this IImageProcessingContext source, float sigma) =>
source.ApplyProcessor(new GaussianSharpenProcessor(sigma));
/// <summary>
/// Applies a Gaussian sharpening filter to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source, float sigma, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext GaussianSharpen(
this IImageProcessingContext source,
float sigma,
Rectangle rectangle) =>
source.ApplyProcessor(new GaussianSharpenProcessor(sigma), rectangle);
}
}
}

27
src/ImageSharp/Processing/GlowExtensions.cs

@ -9,7 +9,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of a radial glow to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of a radial glow on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class GlowExtensions
{
@ -18,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Glow(source, GraphicsOptions.Default);
@ -29,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the glow.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
{
@ -42,7 +43,7 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, float radius)
where TPixel : struct, IPixel<TPixel>
=> Glow(source, GraphicsOptions.Default, radius);
@ -55,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(GraphicsOptions.Default, rectangle);
@ -70,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(GraphicsOptions.Default, color, ValueSize.Absolute(radius), rectangle);
@ -81,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(0.5f));
@ -93,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="color">The color to set as the glow.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, color, ValueSize.PercentageOfWidth(0.5f));
@ -105,7 +106,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, float radius)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, NamedColors<TPixel>.Black, ValueSize.Absolute(radius));
@ -119,7 +120,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(0.5f), rectangle);
@ -135,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, color, ValueSize.Absolute(radius), rectangle);
@ -151,7 +152,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, ValueSize radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GlowProcessor<TPixel>(color, radius, options), rectangle);
@ -164,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="options">The options effecting things like blending.</param>
/// <param name="color">The color to set as the glow.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, ValueSize radius)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GlowProcessor<TPixel>(color, radius, options));

63
src/ImageSharp/Processing/GrayscaleExtensions.cs

@ -9,56 +9,49 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of grayscale toning to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of grayscale toning to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class GrayscaleExtensions
{
/// <summary>
/// Applies <see cref="GrayscaleMode.Bt709"/> grayscale toning to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source)
=> Grayscale(source, GrayscaleMode.Bt709);
/// <summary>
/// Applies <see cref="GrayscaleMode.Bt709"/> grayscale toning to the image using the given amount.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, float amount)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, float amount)
=> Grayscale(source, GrayscaleMode.Bt709, amount);
/// <summary>
/// Applies grayscale toning to the image with the given <see cref="GrayscaleMode"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, GrayscaleMode mode)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, GrayscaleMode mode)
=> Grayscale(source, mode, 1F);
/// <summary>
/// Applies grayscale toning to the image with the given <see cref="GrayscaleMode"/> using the given amount.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, GrayscaleMode mode, float amount)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, GrayscaleMode mode, float amount)
{
IImageProcessor<TPixel> processor = mode == GrayscaleMode.Bt709
? (IImageProcessor<TPixel>)new GrayscaleBt709Processor<TPixel>(amount)
: new GrayscaleBt601Processor<TPixel>(1F);
IImageProcessor processor = mode == GrayscaleMode.Bt709
? (IImageProcessor)new GrayscaleBt709Processor(amount)
: new GrayscaleBt601Processor(1F);
source.ApplyProcessor(processor);
return source;
@ -67,61 +60,53 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Applies <see cref="GrayscaleMode.Bt709"/> grayscale toning to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, Rectangle rectangle)
=> Grayscale(source, 1F, rectangle);
/// <summary>
/// Applies <see cref="GrayscaleMode.Bt709"/> grayscale toning to the image using the given amount.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, float amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> Grayscale(source, GrayscaleMode.Bt709, amount, rectangle);
/// <summary>
/// Applies grayscale toning to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, GrayscaleMode mode, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, GrayscaleMode mode, Rectangle rectangle)
=> Grayscale(source, mode, 1F, rectangle);
/// <summary>
/// Applies grayscale toning to the image using the given amount.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, GrayscaleMode mode, float amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext Grayscale(this IImageProcessingContext source, GrayscaleMode mode, float amount, Rectangle rectangle)
{
IImageProcessor<TPixel> processor = mode == GrayscaleMode.Bt709
? (IImageProcessor<TPixel>)new GrayscaleBt709Processor<TPixel>(amount)
: new GrayscaleBt601Processor<TPixel>(amount);
IImageProcessor processor = mode == GrayscaleMode.Bt709
? (IImageProcessor)new GrayscaleBt709Processor(amount)
: new GrayscaleBt601Processor(amount);
source.ApplyProcessor(processor, rectangle);
return source;

50
src/ImageSharp/Processing/HistogramEqualizationExtension.cs

@ -1,62 +1,32 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Normalization;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extension that allow the adjustment of the contrast of an image via its histogram.
/// Defines extension that allow the adjustment of the contrast of an image via its histogram.
/// </summary>
public static class HistogramEqualizationExtension
{
/// <summary>
/// Equalizes the histogram of an image to increases the contrast.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> HistogramEqualization(source, HistogramEqualizationOptions.Default);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext HistogramEqualization(this IImageProcessingContext source) =>
HistogramEqualization(source, HistogramEqualizationOptions.Default);
/// <summary>
/// Equalizes the histogram of an image to increases the contrast.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The histogram equalization options to use.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source, HistogramEqualizationOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(GetProcessor<TPixel>(options));
private static HistogramEqualizationProcessor<TPixel> GetProcessor<TPixel>(HistogramEqualizationOptions options)
where TPixel : struct, IPixel<TPixel>
{
HistogramEqualizationProcessor<TPixel> processor;
switch (options.Method)
{
case HistogramEqualizationMethod.Global:
processor = new GlobalHistogramEqualizationProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage);
break;
case HistogramEqualizationMethod.AdaptiveTileInterpolation:
processor = new AdaptiveHistEqualizationProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles);
break;
case HistogramEqualizationMethod.AdaptiveSlidingWindow:
processor = new AdaptiveHistEqualizationSWProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles);
break;
default:
processor = new GlobalHistogramEqualizationProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage);
break;
}
return processor;
}
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext HistogramEqualization(
this IImageProcessingContext source,
HistogramEqualizationOptions options) =>
source.ApplyProcessor(HistogramEqualizationProcessor.FromOptions(options));
}
}
}

19
src/ImageSharp/Processing/HueExtensions.cs

@ -8,33 +8,30 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the alteration of the hue component to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the alteration of the hue component of an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class HueExtensions
{
/// <summary>
/// Alters the hue component of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="degrees">The rotation angle in degrees to adjust the hue.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Hue<TPixel>(this IImageProcessingContext<TPixel> source, float degrees)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new HueProcessor<TPixel>(degrees));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Hue(this IImageProcessingContext source, float degrees)
=> source.ApplyProcessor(new HueProcessor(degrees));
/// <summary>
/// Alters the hue component of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="degrees">The rotation angle in degrees to adjust the hue.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Hue<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new HueProcessor<TPixel>(degrees), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Hue(this IImageProcessingContext source, float degrees, Rectangle rectangle)
=> source.ApplyProcessor(new HueProcessor(degrees), rectangle);
}
}

42
src/ImageSharp/Processing/IImageProcessingContext.cs

@ -0,0 +1,42 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// A pixel-agnostic interface to queue up image operations to apply to an image.
/// </summary>
public interface IImageProcessingContext
{
/// <summary>
/// Gets a reference to the <see cref="MemoryAllocator" /> used to allocate buffers
/// for this context.
/// </summary>
MemoryAllocator MemoryAllocator { get; }
/// <summary>
/// Gets the image dimensions at the current point in the processing pipeline.
/// </summary>
/// <returns>The <see cref="Rectangle"/>.</returns>
Size GetCurrentSize();
/// <summary>
/// Adds the processor to the current set of image operations to be applied.
/// </summary>
/// <param name="processor">The processor to apply.</param>
/// <param name="rectangle">The area to apply it to.</param>
/// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle);
/// <summary>
/// Adds the processor to the current set of image operations to be applied.
/// </summary>
/// <param name="processor">The processor to apply.</param>
/// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext ApplyProcessor(IImageProcessor processor);
}
}

21
src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs

@ -3,35 +3,22 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// An interface to queue up image operations to apply to an image.
/// A pixel-specific interface to queue up image operations to apply to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
public interface IImageProcessingContext<TPixel>
public interface IImageProcessingContext<TPixel> : IImageProcessingContext
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets a reference to the <see cref="MemoryAllocator" /> used to allocate buffers
/// for this context.
/// </summary>
MemoryAllocator MemoryAllocator { get; }
/// <summary>
/// Gets the image dimensions at the current point in the processing pipeline.
/// </summary>
/// <returns>The <see cref="Rectangle"/></returns>
Size GetCurrentSize();
/// <summary>
/// Adds the processor to the current set of image operations to be applied.
/// </summary>
/// <param name="processor">The processor to apply</param>
/// <param name="rectangle">The area to apply it to</param>
/// <param name="processor">The processor to apply.</param>
/// <param name="rectangle">The area to apply it to.</param>
/// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle);

19
src/ImageSharp/Processing/InvertExtensions.cs

@ -8,31 +8,28 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the inversion of colors to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the inversion of colors of an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class InvertExtensions
{
/// <summary>
/// Inverts the colors of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Invert<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new InvertProcessor<TPixel>(1F));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Invert(this IImageProcessingContext source)
=> source.ApplyProcessor(new InvertProcessor(1F));
/// <summary>
/// Inverts the colors of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Invert<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new InvertProcessor<TPixel>(1F), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Invert(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new InvertProcessor(1F), rectangle);
}
}

19
src/ImageSharp/Processing/KodachromeExtensions.cs

@ -8,31 +8,28 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the recreation of an old Kodachrome camera effect to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the recreation of an old Kodachrome camera effect on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class KodachromeExtensions
{
/// <summary>
/// Alters the colors of the image recreating an old Kodachrome camera effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Kodachrome<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new KodachromeProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Kodachrome(this IImageProcessingContext source)
=> source.ApplyProcessor(new KodachromeProcessor());
/// <summary>
/// Alters the colors of the image recreating an old Kodachrome camera effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Kodachrome<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new KodachromeProcessor<TPixel>(), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Kodachrome(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new KodachromeProcessor(), rectangle);
}
}

19
src/ImageSharp/Processing/LomographExtensions.cs

@ -8,31 +8,28 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the recreation of an old Lomograph camera effect to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the recreation of an old Lomograph camera effect on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class LomographExtensions
{
/// <summary>
/// Alters the colors of the image recreating an old Lomograph camera effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Lomograph<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new LomographProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Lomograph(this IImageProcessingContext source)
=> source.ApplyProcessor(new LomographProcessor());
/// <summary>
/// Alters the colors of the image recreating an old Lomograph camera effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Lomograph<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new LomographProcessor<TPixel>(), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Lomograph(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new LomographProcessor(), rectangle);
}
}

40
src/ImageSharp/Processing/OilPaintExtensions.cs

@ -1,14 +1,14 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Effects;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds oil painting effect extensions to the <see cref="Image{TPixel}"/> type.
/// Defines oil painting effect extensions applicable on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class OilPaintExtensions
{
@ -16,52 +16,48 @@ namespace SixLabors.ImageSharp.Processing
/// Alters the colors of the image recreating an oil painting effect with levels and brushSize
/// set to <value>10</value> and <value>15</value> respectively.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> OilPaint(source, 10, 15);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext OilPaint(this IImageProcessingContext source) => OilPaint(source, 10, 15);
/// <summary>
/// Alters the colors of the image recreating an oil painting effect with levels and brushSize
/// set to <value>10</value> and <value>15</value> respectively.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> OilPaint(source, 10, 15, rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext OilPaint(this IImageProcessingContext source, Rectangle rectangle) =>
OilPaint(source, 10, 15, rectangle);
/// <summary>
/// Alters the colors of the image recreating an oil painting effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="levels">The number of intensity levels. Higher values result in a broader range of color intensities forming part of the result image.</param>
/// <param name="brushSize">The number of neighboring pixels used in calculating each individual pixel value.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source, int levels, int brushSize)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OilPaintingProcessor<TPixel>(levels, brushSize));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext
OilPaint(this IImageProcessingContext source, int levels, int brushSize) =>
source.ApplyProcessor(new OilPaintingProcessor(levels, brushSize));
/// <summary>
/// Alters the colors of the image recreating an oil painting effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="levels">The number of intensity levels. Higher values result in a broader range of color intensities forming part of the result image.</param>
/// <param name="brushSize">The number of neighboring pixels used in calculating each individual pixel value.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source, int levels, int brushSize, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OilPaintingProcessor<TPixel>(levels, brushSize), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext OilPaint(
this IImageProcessingContext source,
int levels,
int brushSize,
Rectangle rectangle) =>
source.ApplyProcessor(new OilPaintingProcessor(levels, brushSize), rectangle);
}
}

19
src/ImageSharp/Processing/OpacityExtensions.cs

@ -8,33 +8,30 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the alteration of the opacity component to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the alteration of the opacity component of an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class OpacityExtensions
{
/// <summary>
/// Multiplies the alpha component of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Opacity<TPixel>(this IImageProcessingContext<TPixel> source, float amount)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OpacityProcessor<TPixel>(amount));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Opacity(this IImageProcessingContext source, float amount)
=> source.ApplyProcessor(new OpacityProcessor(amount));
/// <summary>
/// Multiplies the alpha component of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Opacity<TPixel>(this IImageProcessingContext<TPixel> source, float amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OpacityProcessor<TPixel>(amount), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Opacity(this IImageProcessingContext source, float amount, Rectangle rectangle)
=> source.ApplyProcessor(new OpacityProcessor(amount), rectangle);
}
}

11
src/ImageSharp/Processing/PadExtensions.cs

@ -7,26 +7,25 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the application of padding operations to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the application of padding operations on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class PadExtensions
{
/// <summary>
/// Evenly pads an image to fit the new dimensions.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The source image to pad.</param>
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Pad<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Pad(this IImageProcessingContext source, int width, int height)
{
var options = new ResizeOptions
{
Size = new Size(width, height),
Mode = ResizeMode.BoxPad,
Sampler = KnownResamplers.NearestNeighbor
Sampler = KnownResamplers.NearestNeighbor,
};
return source.Resize(options);

30
src/ImageSharp/Processing/PixelateExtensions.cs

@ -1,50 +1,46 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Effects;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds pixelation effect extensions to the <see cref="Image{TPixel}"/> type.
/// Defines pixelation effect extensions applicable on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class PixelateExtensions
{
/// <summary>
/// Pixelates an image with the given pixel size.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Pixelate(source, 4);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Pixelate(this IImageProcessingContext source) => Pixelate(source, 4);
/// <summary>
/// Pixelates an image with the given pixel size.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="size">The size of the pixels.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source, int size)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(size));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Pixelate(this IImageProcessingContext source, int size) =>
source.ApplyProcessor(new PixelateProcessor(size));
/// <summary>
/// Pixelates an image with the given pixel size.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="size">The size of the pixels.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source, int size, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(size), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Pixelate(
this IImageProcessingContext source,
int size,
Rectangle rectangle) =>
source.ApplyProcessor(new PixelateProcessor(size), rectangle);
}
}

19
src/ImageSharp/Processing/PolaroidExtensions.cs

@ -8,31 +8,28 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds extensions that allow the recreation of an old Polaroid camera effect to the <see cref="Image{TPixel}"/> type.
/// Defines extensions that allow the recreation of an old Polaroid camera effect on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class PolaroidExtensions
{
/// <summary>
/// Alters the colors of the image recreating an old Polaroid camera effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Polaroid<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new PolaroidProcessor<TPixel>());
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Polaroid(this IImageProcessingContext source)
=> source.ApplyProcessor(new PolaroidProcessor());
/// <summary>
/// Alters the colors of the image recreating an old Polaroid camera effect.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Polaroid<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new PolaroidProcessor<TPixel>(), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Polaroid(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new PolaroidProcessor(), rectangle);
}
}

48
src/ImageSharp/Processing/ProcessingExtensions.cs

@ -25,6 +25,17 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext<TPixel> Apply<TPixel>(this IImageProcessingContext<TPixel> source, Action<Image<TPixel>> operation)
where TPixel : struct, IPixel<TPixel> => source.ApplyProcessor(new DelegateProcessor<TPixel>(operation));
/// <summary>
/// Mutates the source image by applying the image operation to it.
/// </summary>
/// <param name="source">The image to mutate.</param>
/// <param name="operation">The operation to perform on the source.</param>
public static void Mutate(this Image source, Action<IImageProcessingContext> operation)
{
ProcessingVisitor visitor = new ProcessingVisitor(operation, true);
source.AcceptVisitor(visitor);
}
/// <summary>
/// Mutates the source image by applying the image operation to it.
/// </summary>
@ -59,6 +70,19 @@ namespace SixLabors.ImageSharp.Processing
operationsRunner.Apply();
}
/// <summary>
/// Creates a deep clone of the current image. The clone is then mutated by the given operation.
/// </summary>
/// <param name="source">The image to clone.</param>
/// <param name="operation">The operation to perform on the clone.</param>
/// <returns>The new <see cref="SixLabors.ImageSharp.Image"/>.</returns>
public static Image Clone(this Image source, Action<IImageProcessingContext> operation)
{
ProcessingVisitor visitor = new ProcessingVisitor(operation, false);
source.AcceptVisitor(visitor);
return visitor.ResultImage;
}
/// <summary>
/// Creates a deep clone of the current image. The clone is then mutated by the given operation.
/// </summary>
@ -112,5 +136,29 @@ namespace SixLabors.ImageSharp.Processing
return source;
}
private class ProcessingVisitor : IImageVisitor
{
private readonly Action<IImageProcessingContext> operation;
private readonly bool mutate;
public ProcessingVisitor(Action<IImageProcessingContext> operation, bool mutate)
{
this.operation = operation;
this.mutate = mutate;
}
public Image ResultImage { get; private set; }
public void Visit<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
IInternalImageProcessingContext<TPixel> operationsRunner = image.GetConfiguration()
.ImageOperationsProvider.CreateImageProcessingContext(image, this.mutate);
this.operation(operationsRunner);
this.ResultImage = operationsRunner.Apply();
}
}
}
}

53
src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs

@ -3,67 +3,48 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies box blur processing to the image.
/// Defines a box blur processor of a given Radius.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BoxBlurProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class BoxBlurProcessor : IImageProcessor
{
/// <summary>
/// The maximum size of the kernel in either direction.
/// The default radius used by the parameterless constructor.
/// </summary>
private readonly int kernelSize;
public const int DefaultRadius = 7;
/// <summary>
/// Initializes a new instance of the <see cref="BoxBlurProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BoxBlurProcessor"/> class.
/// </summary>
/// <param name="radius">
/// The 'radius' value representing the size of the area to sample.
/// </param>
public BoxBlurProcessor(int radius = 7)
public BoxBlurProcessor(int radius)
{
this.Radius = radius;
this.kernelSize = (radius * 2) + 1;
this.KernelX = this.CreateBoxKernel();
this.KernelY = this.KernelX.Transpose();
}
/// <summary>
/// Gets the Radius
/// Initializes a new instance of the <see cref="BoxBlurProcessor"/> class.
/// </summary>
public int Radius { get; }
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public DenseMatrix<float> KernelX { get; }
public BoxBlurProcessor()
: this(DefaultRadius)
{
}
/// <summary>
/// Gets the vertical gradient operator.
/// Gets the Radius.
/// </summary>
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(source, sourceRectangle, configuration);
public int Radius { get; }
/// <summary>
/// Create a 1 dimensional Box kernel.
/// </summary>
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
private DenseMatrix<float> CreateBoxKernel()
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
int size = this.kernelSize;
var kernel = new DenseMatrix<float>(size, 1);
kernel.Fill(1F / size);
return kernel;
return new BoxBlurProcessor<TPixel>(this);
}
}
}

63
src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies box blur processing to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BoxBlurProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly BoxBlurProcessor definition;
/// <summary>
/// Initializes a new instance of the <see cref="BoxBlurProcessor{TPixel}"/> class.
/// </summary>
/// <param name="definition">The <see cref="BoxBlurProcessor"/> defining the processor parameters.</param>
public BoxBlurProcessor(BoxBlurProcessor definition)
{
this.definition = definition;
int kernelSize = (definition.Radius * 2) + 1;
this.KernelX = CreateBoxKernel(kernelSize);
this.KernelY = this.KernelX.Transpose();
}
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration) =>
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(
source,
sourceRectangle,
configuration);
/// <summary>
/// Create a 1 dimensional Box kernel.
/// </summary>
/// <param name="kernelSize">The maximum size of the kernel in either direction.</param>
/// <returns>The <see cref="DenseMatrix{T}"/>.</returns>
private static DenseMatrix<float> CreateBoxKernel(int kernelSize)
{
var kernel = new DenseMatrix<float>(kernelSize, 1);
kernel.Fill(1F / kernelSize);
return kernel;
}
}
}

3
src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs → src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs

@ -1,9 +1,10 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;

0
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs → src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs

93
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs

@ -0,0 +1,93 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
internal static class ConvolutionProcessorHelpers
{
/// <summary>
/// Kernel radius is calculated using the minimum viable value.
/// See <see href="http://chemaguerra.com/gaussian-filter-radius/"/>.
/// </summary>
internal static int GetDefaultGaussianRadius(float sigma)
{
return (int)MathF.Ceiling(sigma * 3);
}
/// <summary>
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function.
/// </summary>
/// <returns>The <see cref="DenseMatrix{T}"/>.</returns>
internal static DenseMatrix<float> CreateGaussianBlurKernel(int size, float weight)
{
var kernel = new DenseMatrix<float>(size, 1);
float sum = 0F;
float midpoint = (size - 1) / 2F;
for (int i = 0; i < size; i++)
{
float x = i - midpoint;
float gx = ImageMaths.Gaussian(x, weight);
sum += gx;
kernel[0, i] = gx;
}
// Normalize kernel so that the sum of all weights equals 1
for (int i = 0; i < size; i++)
{
kernel[0, i] /= sum;
}
return kernel;
}
/// <summary>
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
/// </summary>
/// <returns>The <see cref="DenseMatrix{T}"/>.</returns>
internal static DenseMatrix<float> CreateGaussianSharpenKernel(int size, float weight)
{
var kernel = new DenseMatrix<float>(size, 1);
float sum = 0;
float midpoint = (size - 1) / 2F;
for (int i = 0; i < size; i++)
{
float x = i - midpoint;
float gx = ImageMaths.Gaussian(x, weight);
sum += gx;
kernel[0, i] = gx;
}
// Invert the kernel for sharpening.
int midpointRounded = (int)midpoint;
for (int i = 0; i < size; i++)
{
if (i == midpointRounded)
{
// Calculate central value
kernel[0, i] = (2F * sum) - kernel[0, i];
}
else
{
// invert value
kernel[0, i] = -kernel[0, i];
}
}
// Normalize kernel so that the sum of all weights equals 1
for (int i = 0; i < size; i++)
{
kernel[0, i] /= sum;
}
return kernel;
}
}
}

0
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs → src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs

7
src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs → src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Defines a processor that detects edges within an image using two one-dimensional matrices.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class EdgeDetector2DProcessor<TPixel> : ImageProcessor<TPixel>, IEdgeDetectorProcessor<TPixel>
internal class EdgeDetector2DProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <param name="kernelX">The horizontal gradient operator.</param>
/// <param name="kernelY">The vertical gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetector2DProcessor(in DenseMatrix<float> kernelX, in DenseMatrix<float> kernelY, bool grayscale)
internal EdgeDetector2DProcessor(in DenseMatrix<float> kernelX, in DenseMatrix<float> kernelY, bool grayscale)
{
Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same.");
this.KernelX = kernelX;
@ -39,7 +39,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// </summary>
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
public bool Grayscale { get; }
/// <inheritdoc />
@ -51,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
if (this.Grayscale)
{
new GrayscaleBt709Processor<TPixel>(1F).Apply(source, sourceRectangle, configuration);
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
}
}
}

56
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs → src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs

@ -19,71 +19,37 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Defines a processor that detects edges within an image using a eight two dimensional matrices.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>, IEdgeDetectorProcessor<TPixel>
internal class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="EdgeDetectorCompassProcessor{TPixel}"/> class.
/// </summary>
/// <param name="kernels">Gets the kernels to use.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorCompassProcessor(bool grayscale) => this.Grayscale = grayscale;
/// <summary>
/// Gets the North gradient operator
/// </summary>
public abstract DenseMatrix<float> North { get; }
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public abstract DenseMatrix<float> NorthWest { get; }
/// <summary>
/// Gets the West gradient operator
/// </summary>
public abstract DenseMatrix<float> West { get; }
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public abstract DenseMatrix<float> SouthWest { get; }
/// <summary>
/// Gets the South gradient operator
/// </summary>
public abstract DenseMatrix<float> South { get; }
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public abstract DenseMatrix<float> SouthEast { get; }
/// <summary>
/// Gets the East gradient operator
/// </summary>
public abstract DenseMatrix<float> East { get; }
internal EdgeDetectorCompassProcessor(CompassKernels kernels, bool grayscale)
{
this.Grayscale = grayscale;
this.Kernels = kernels;
}
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public abstract DenseMatrix<float> NorthEast { get; }
private CompassKernels Kernels { get; }
/// <inheritdoc/>
public bool Grayscale { get; }
private bool Grayscale { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
if (this.Grayscale)
{
new GrayscaleBt709Processor<TPixel>(1F).Apply(source, sourceRectangle, configuration);
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
}
}
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
DenseMatrix<float>[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
DenseMatrix<float>[] kernels = this.Kernels.Flatten();
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;

37
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs

@ -2,49 +2,30 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Filters;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Defines a processor that detects edges within an image using a single two dimensional matrix.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class EdgeDetectorProcessor<TPixel> : ImageProcessor<TPixel>, IEdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public abstract class EdgeDetectorProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor"/> class.
/// </summary>
/// <param name="kernelXY">The 2d gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorProcessor(in DenseMatrix<float> kernelXY, bool grayscale)
/// <param name="grayscale">A value indicating whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorProcessor(bool grayscale)
{
this.KernelXY = kernelXY;
this.Grayscale = grayscale;
}
/// <inheritdoc/>
public bool Grayscale { get; }
/// <summary>
/// Gets the 2d gradient operator.
/// Gets a value indicating whether to convert the image to grayscale before performing edge detection.
/// </summary>
public DenseMatrix<float> KernelXY { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
if (this.Grayscale)
{
new GrayscaleBt709Processor<TPixel>(1F).Apply(source, sourceRectangle, configuration);
}
}
public bool Grayscale { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new ConvolutionProcessor<TPixel>(this.KernelXY, true).Apply(source, sourceRectangle, configuration);
/// <inheritdoc />
public abstract IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>;
}
}

49
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs

@ -0,0 +1,49 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Filters;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Defines a processor that detects edges within an image using a single two dimensional matrix.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class EdgeDetectorProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor{TPixel}"/> class.
/// </summary>
/// <param name="kernelXY">The 2d gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public EdgeDetectorProcessor(in DenseMatrix<float> kernelXY, bool grayscale)
{
this.KernelXY = kernelXY;
this.Grayscale = grayscale;
}
public bool Grayscale { get; }
/// <summary>
/// Gets the 2d gradient operator.
/// </summary>
public DenseMatrix<float> KernelXY { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
}
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new ConvolutionProcessor<TPixel>(this.KernelXY, true).Apply(source, sourceRectangle, configuration);
}
}

80
src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs

@ -1,38 +1,40 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies Gaussian blur processing to the image.
/// Defines Gaussian blur by a (Sigma, Radius) pair.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class GaussianBlurProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class GaussianBlurProcessor : IImageProcessor
{
/// <summary>
/// The maximum size of the kernel in either direction.
/// The default value for <see cref="Sigma"/>.
/// </summary>
private readonly int kernelSize;
public const float DefaultSigma = 3f;
/// <summary>
/// Initializes a new instance of the <see cref="GaussianBlurProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="GaussianBlurProcessor"/> class.
/// </summary>
public GaussianBlurProcessor()
: this(DefaultSigma, ConvolutionProcessorHelpers.GetDefaultGaussianRadius(DefaultSigma))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GaussianBlurProcessor"/> class.
/// </summary>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
public GaussianBlurProcessor(float sigma = 3F)
: this(sigma, (int)MathF.Ceiling(sigma * 3))
public GaussianBlurProcessor(float sigma)
: this(sigma, ConvolutionProcessorHelpers.GetDefaultGaussianRadius(sigma))
{
// Kernel radius is calculated using the minimum viable value.
// http://chemaguerra.com/gaussian-filter-radius/
}
/// <summary>
/// Initializes a new instance of the <see cref="GaussianBlurProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="GaussianBlurProcessor"/> class.
/// </summary>
/// <param name="radius">
/// The 'radius' value representing the size of the area to sample.
@ -43,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
/// <summary>
/// Initializes a new instance of the <see cref="GaussianBlurProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="GaussianBlurProcessor"/> class.
/// </summary>
/// <param name="sigma">
/// The 'sigma' value representing the weight of the blur.
@ -54,10 +56,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// </param>
public GaussianBlurProcessor(float sigma, int radius)
{
this.kernelSize = (radius * 2) + 1;
this.Sigma = sigma;
this.KernelX = this.CreateGaussianKernel();
this.KernelY = this.KernelX.Transpose();
this.Radius = radius;
}
/// <summary>
@ -66,47 +66,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
public float Sigma { get; }
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// Gets the radius defining the size of the area to sample.
/// </summary>
public DenseMatrix<float> KernelY { get; }
public int Radius { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(source, sourceRectangle, configuration);
/// <summary>
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
/// </summary>
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
private DenseMatrix<float> CreateGaussianKernel()
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
int size = this.kernelSize;
float weight = this.Sigma;
var kernel = new DenseMatrix<float>(size, 1);
float sum = 0F;
float midpoint = (size - 1) / 2F;
for (int i = 0; i < size; i++)
{
float x = i - midpoint;
float gx = ImageMaths.Gaussian(x, weight);
sum += gx;
kernel[0, i] = gx;
}
// Normalize kernel so that the sum of all weights equals 1
for (int i = 0; i < size; i++)
{
kernel[0, i] /= sum;
}
return kernel;
return new GaussianBlurProcessor<TPixel>(this);
}
}
}

48
src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs

@ -0,0 +1,48 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies Gaussian blur processing to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class GaussianBlurProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="GaussianBlurProcessor{TPixel}"/> class.
/// </summary>
/// <param name="definition">The <see cref="GaussianBlurProcessor"/> defining the processor parameters.</param>
public GaussianBlurProcessor(GaussianBlurProcessor definition)
{
int kernelSize = (definition.Radius * 2) + 1;
this.KernelX = ConvolutionProcessorHelpers.CreateGaussianBlurKernel(kernelSize, definition.Sigma);
this.KernelY = this.KernelX.Transpose();
}
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration) =>
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(
source,
sourceRectangle,
configuration);
}
}

102
src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs

@ -3,38 +3,38 @@
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies Gaussian sharpening processing to the image.
/// Defines Gaussian sharpening by a (Sigma, Radius) pair.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class GaussianSharpenProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class GaussianSharpenProcessor : IImageProcessor
{
/// <summary>
/// The default value for <see cref="Sigma"/>.
/// </summary>
public const float DefaultSigma = 3f;
/// <summary>
/// The maximum size of the kernel in either direction.
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor"/> class.
/// </summary>
private readonly int kernelSize;
public GaussianSharpenProcessor()
: this(DefaultSigma, ConvolutionProcessorHelpers.GetDefaultGaussianRadius(DefaultSigma))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor"/> class.
/// </summary>
/// <param name="sigma">
/// The 'sigma' value representing the weight of the sharpening.
/// </param>
public GaussianSharpenProcessor(float sigma = 3F)
: this(sigma, (int)MathF.Ceiling(sigma * 3))
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
public GaussianSharpenProcessor(float sigma)
: this(sigma, ConvolutionProcessorHelpers.GetDefaultGaussianRadius(sigma))
{
// Kernel radius is calculated using the minimum viable value.
// http://chemaguerra.com/gaussian-filter-radius/
}
/// <summary>
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor"/> class.
/// </summary>
/// <param name="radius">
/// The 'radius' value representing the size of the area to sample.
@ -45,10 +45,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
/// <summary>
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor"/> class.
/// </summary>
/// <param name="sigma">
/// The 'sigma' value representing the weight of the sharpen.
/// The 'sigma' value representing the weight of the blur.
/// </param>
/// <param name="radius">
/// The 'radius' value representing the size of the area to sample.
@ -56,10 +56,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// </param>
public GaussianSharpenProcessor(float sigma, int radius)
{
this.kernelSize = (radius * 2) + 1;
this.Sigma = sigma;
this.KernelX = this.CreateGaussianKernel();
this.KernelY = this.KernelX.Transpose();
this.Radius = radius;
}
/// <summary>
@ -68,63 +66,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
public float Sigma { get; }
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// Gets the radius defining the size of the area to sample.
/// </summary>
public DenseMatrix<float> KernelY { get; }
public int Radius { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(source, sourceRectangle, configuration);
/// <summary>
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
/// </summary>
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
private DenseMatrix<float> CreateGaussianKernel()
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
int size = this.kernelSize;
float weight = this.Sigma;
var kernel = new DenseMatrix<float>(size, 1);
float sum = 0;
float midpoint = (size - 1) / 2F;
for (int i = 0; i < size; i++)
{
float x = i - midpoint;
float gx = ImageMaths.Gaussian(x, weight);
sum += gx;
kernel[0, i] = gx;
}
// Invert the kernel for sharpening.
int midpointRounded = (int)midpoint;
for (int i = 0; i < size; i++)
{
if (i == midpointRounded)
{
// Calculate central value
kernel[0, i] = (2F * sum) - kernel[0, i];
}
else
{
// invert value
kernel[0, i] = -kernel[0, i];
}
}
// Normalize kernel so that the sum of all weights equals 1
for (int i = 0; i < size; i++)
{
kernel[0, i] /= sum;
}
return kernel;
return new GaussianSharpenProcessor<TPixel>(this);
}
}
}

42
src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs

@ -0,0 +1,42 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies Gaussian sharpening processing to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class GaussianSharpenProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor{TPixel}"/> class.
/// </summary>
/// <param name="definition">The <see cref="GaussianBlurProcessor"/> defining the processor parameters.</param>
public GaussianSharpenProcessor(GaussianSharpenProcessor definition)
{
int kernelSize = (definition.Radius * 2) + 1;
this.KernelX = ConvolutionProcessorHelpers.CreateGaussianSharpenKernel(kernelSize, definition.Sigma);
this.KernelY = this.KernelX.Transpose();
}
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(source, sourceRectangle, configuration);
}
}

28
src/ImageSharp/Processing/Processors/Convolution/IEdgeDetectorProcessor.cs

@ -1,28 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Provides properties and methods allowing the detection of edges within an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public interface IEdgeDetectorProcessor<TPixel> : IImageProcessor<TPixel>, IEdgeDetectorProcessor
where TPixel : struct, IPixel<TPixel>
{
}
/// <summary>
/// Provides properties and methods allowing the detection of edges within an image.
/// </summary>
public interface IEdgeDetectorProcessor
{
/// <summary>
/// Gets a value indicating whether to convert the image to grayscale before performing edge detection.
/// </summary>
bool Grayscale { get; }
}
}

22
src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs

@ -1,24 +1,30 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Kayyali operator filter. <see href="http://edgedetection.webs.com/"/>
/// Defines edge detection processing using the Kayyali operator filter.
/// See <see href="http://edgedetection.webs.com/"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class KayyaliProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class KayyaliProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="KayyaliProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="KayyaliProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public KayyaliProcessor(bool grayscale)
: base(KayyaliKernels.KayyaliX, KayyaliKernels.KayyaliY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(
KayyaliKernels.KayyaliX,
KayyaliKernels.KayyaliY,
this.Grayscale);
}
}
}

57
src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
internal abstract class CompassKernels
{
/// <summary>
/// Gets the North gradient operator.
/// </summary>
public abstract DenseMatrix<float> North { get; }
/// <summary>
/// Gets the NorthWest gradient operator.
/// </summary>
public abstract DenseMatrix<float> NorthWest { get; }
/// <summary>
/// Gets the West gradient operator.
/// </summary>
public abstract DenseMatrix<float> West { get; }
/// <summary>
/// Gets the SouthWest gradient operator.
/// </summary>
public abstract DenseMatrix<float> SouthWest { get; }
/// <summary>
/// Gets the South gradient operator.
/// </summary>
public abstract DenseMatrix<float> South { get; }
/// <summary>
/// Gets the SouthEast gradient operator.
/// </summary>
public abstract DenseMatrix<float> SouthEast { get; }
/// <summary>
/// Gets the East gradient operator.
/// </summary>
public abstract DenseMatrix<float> East { get; }
/// <summary>
/// Gets the NorthEast gradient operator.
/// </summary>
public abstract DenseMatrix<float> NorthEast { get; }
public DenseMatrix<float>[] Flatten() =>
new[]
{
this.North, this.NorthWest, this.West, this.SouthWest,
this.South, this.SouthEast, this.East, this.NorthEast
};
}
}

0
src/ImageSharp/Processing/Processors/Convolution/KayyaliKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs

18
src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs

@ -8,12 +8,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Contains the eight matrices used for Kirsch edge detection
/// </summary>
internal static class KirschKernels
internal class KirschKernels : CompassKernels
{
/// <summary>
/// Gets the North gradient operator
/// </summary>
public static DenseMatrix<float> KirschNorth =>
public override DenseMatrix<float> North =>
new float[,]
{
{ 5, 5, 5 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public static DenseMatrix<float> KirschNorthWest =>
public override DenseMatrix<float> NorthWest =>
new float[,]
{
{ 5, 5, -3 },
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the West gradient operator
/// </summary>
public static DenseMatrix<float> KirschWest =>
public override DenseMatrix<float> West =>
new float[,]
{
{ 5, -3, -3 },
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public static DenseMatrix<float> KirschSouthWest =>
public override DenseMatrix<float> SouthWest =>
new float[,]
{
{ -3, -3, -3 },
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the South gradient operator
/// </summary>
public static DenseMatrix<float> KirschSouth =>
public override DenseMatrix<float> South =>
new float[,]
{
{ -3, -3, -3 },
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public static DenseMatrix<float> KirschSouthEast =>
public override DenseMatrix<float> SouthEast =>
new float[,]
{
{ -3, -3, -3 },
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the East gradient operator
/// </summary>
public static DenseMatrix<float> KirschEast =>
public override DenseMatrix<float> East =>
new float[,]
{
{ -3, -3, 5 },
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public static DenseMatrix<float> KirschNorthEast =>
public override DenseMatrix<float> NorthEast =>
new float[,]
{
{ -3, 5, 5 },

0
src/ImageSharp/Processing/Processors/Convolution/LaplacianKernelFactory.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs

0
src/ImageSharp/Processing/Processors/Convolution/LaplacianKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs

0
src/ImageSharp/Processing/Processors/Convolution/PrewittKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs

0
src/ImageSharp/Processing/Processors/Convolution/RobertsCrossKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs

20
src/ImageSharp/Processing/Processors/Convolution/RobinsonKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs

@ -6,14 +6,14 @@ using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Contains the kernels used for Robinson edge detection
/// Contains the kernels used for Robinson edge detection.
/// </summary>
internal static class RobinsonKernels
internal class RobinsonKernels : CompassKernels
{
/// <summary>
/// Gets the North gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonNorth =>
public override DenseMatrix<float> North =>
new float[,]
{
{ 1, 2, 1 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonNorthWest =>
public override DenseMatrix<float> NorthWest =>
new float[,]
{
{ 2, 1, 0 },
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the West gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonWest =>
public override DenseMatrix<float> West =>
new float[,]
{
{ 1, 0, -1 },
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonSouthWest =>
public override DenseMatrix<float> SouthWest =>
new float[,]
{
{ 0, -1, -2 },
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the South gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonSouth =>
public override DenseMatrix<float> South =>
new float[,]
{
{ -1, -2, -1 },
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonSouthEast =>
public override DenseMatrix<float> SouthEast =>
new float[,]
{
{ -2, -1, 0 },
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the East gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonEast =>
public override DenseMatrix<float> East =>
new float[,]
{
{ -1, 0, 1 },
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonNorthEast =>
public override DenseMatrix<float> NorthEast =>
new float[,]
{
{ 0, 1, 2 },

0
src/ImageSharp/Processing/Processors/Convolution/ScharrKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs

0
src/ImageSharp/Processing/Processors/Convolution/SobelKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs

40
src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs

@ -1,20 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Kirsch operator filter. <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>
/// Defines edge detection using the Kirsch operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class KirschProcessor<TPixel> : EdgeDetectorCompassProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class KirschProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="KirschProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="KirschProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public KirschProcessor(bool grayscale)
@ -22,28 +18,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
}
/// <inheritdoc/>
public override DenseMatrix<float> North => KirschKernels.KirschNorth;
/// <inheritdoc/>
public override DenseMatrix<float> NorthWest => KirschKernels.KirschNorthWest;
/// <inheritdoc/>
public override DenseMatrix<float> West => KirschKernels.KirschWest;
/// <inheritdoc/>
public override DenseMatrix<float> SouthWest => KirschKernels.KirschSouthWest;
/// <inheritdoc/>
public override DenseMatrix<float> South => KirschKernels.KirschSouth;
/// <inheritdoc/>
public override DenseMatrix<float> SouthEast => KirschKernels.KirschSouthEast;
/// <inheritdoc/>
public override DenseMatrix<float> East => KirschKernels.KirschEast;
/// <inheritdoc/>
public override DenseMatrix<float> NorthEast => KirschKernels.KirschNorthEast;
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorCompassProcessor<TPixel>(new KirschKernels(), this.Grayscale);
}
}
}

14
src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs

@ -9,17 +9,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Applies edge detection processing to the image using the Laplacian 3x3 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class Laplacian3x3Processor<TPixel> : EdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class Laplacian3x3Processor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="Laplacian3x3Processor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Laplacian3x3Processor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public Laplacian3x3Processor(bool grayscale)
: base(LaplacianKernels.Laplacian3x3, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.Laplacian3x3, this.Grayscale);
}
}
}

20
src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs

@ -1,25 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Laplacian 5x5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// Defines edge detection processing using the Laplacian 5x5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class Laplacian5x5Processor<TPixel> : EdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class Laplacian5x5Processor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="Laplacian5x5Processor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Laplacian5x5Processor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public Laplacian5x5Processor(bool grayscale)
: base(LaplacianKernels.Laplacian5x5, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.Laplacian5x5, this.Grayscale);
}
}
}

18
src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs

@ -1,25 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Laplacian of Gaussian operator filter.
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>
/// See <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class LaplacianOfGaussianProcessor<TPixel> : EdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class LaplacianOfGaussianProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="LaplacianOfGaussianProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="LaplacianOfGaussianProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public LaplacianOfGaussianProcessor(bool grayscale)
: base(LaplacianKernels.LaplacianOfGaussianXY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale);
}
}
}

20
src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs

@ -1,25 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Prewitt operator filter.
/// <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>
/// Defines edge detection using the Prewitt operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class PrewittProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class PrewittProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="PrewittProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="PrewittProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public PrewittProcessor(bool grayscale)
: base(PrewittKernels.PrewittX, PrewittKernels.PrewittY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(PrewittKernels.PrewittX, PrewittKernels.PrewittY, this.Grayscale);
}
}
}

18
src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs

@ -6,20 +6,24 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Roberts Cross operator filter.
/// <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>
/// Defines edge detection processing using the Roberts Cross operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class RobertsCrossProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class RobertsCrossProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="RobertsCrossProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="RobertsCrossProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public RobertsCrossProcessor(bool grayscale)
: base(RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY, this.Grayscale);
}
}
}

38
src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs

@ -7,15 +7,13 @@ using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Robinson operator filter.
/// <see href="http://www.tutorialspoint.com/dip/Robinson_Compass_Mask.htm"/>
/// Defines edge detection using the Robinson operator filter.
/// See <see href="http://www.tutorialspoint.com/dip/Robinson_Compass_Mask.htm"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class RobinsonProcessor<TPixel> : EdgeDetectorCompassProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class RobinsonProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="RobinsonProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="RobinsonProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public RobinsonProcessor(bool grayscale)
@ -23,28 +21,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
}
/// <inheritdoc/>
public override DenseMatrix<float> North => RobinsonKernels.RobinsonNorth;
/// <inheritdoc/>
public override DenseMatrix<float> NorthWest => RobinsonKernels.RobinsonNorthWest;
/// <inheritdoc/>
public override DenseMatrix<float> West => RobinsonKernels.RobinsonWest;
/// <inheritdoc/>
public override DenseMatrix<float> SouthWest => RobinsonKernels.RobinsonSouthWest;
/// <inheritdoc/>
public override DenseMatrix<float> South => RobinsonKernels.RobinsonSouth;
/// <inheritdoc/>
public override DenseMatrix<float> SouthEast => RobinsonKernels.RobinsonSouthEast;
/// <inheritdoc/>
public override DenseMatrix<float> East => RobinsonKernels.RobinsonEast;
/// <inheritdoc/>
public override DenseMatrix<float> NorthEast => RobinsonKernels.RobinsonNorthEast;
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorCompassProcessor<TPixel>(new RobinsonKernels(), this.Grayscale);
}
}
}

16
src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs

@ -6,20 +6,24 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Scharr operator filter.
/// Defines edge detection processing using the Scharr operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class ScharrProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class ScharrProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="ScharrProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="ScharrProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public ScharrProcessor(bool grayscale)
: base(ScharrKernels.ScharrX, ScharrKernels.ScharrY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(ScharrKernels.ScharrX, ScharrKernels.ScharrY, this.Grayscale);
}
}
}

27
src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs

@ -2,24 +2,37 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// The Sobel operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>
/// Defines edge detection using the Sobel operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class SobelProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class SobelProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="SobelProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="SobelProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public SobelProcessor(bool grayscale)
: base(SobelKernels.SobelX, SobelKernels.SobelY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale);
}
// TODO: Move this to an appropriate extension method if possible.
internal void ApplyToFrame<TPixel>(ImageFrame<TPixel> frame, Rectangle sourceRectangle, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
var processorImpl = new EdgeDetector2DProcessor<TPixel>(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale);
processorImpl.Apply(frame, sourceRectangle, configuration);
}
}
}

6
src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs

@ -21,12 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
private readonly Vector4 divisorVector;
/// <summary>
/// The matrix width
/// The matrix width.
/// </summary>
private readonly int matrixHeight;
/// <summary>
/// The matrix height
/// The matrix height.
/// </summary>
private readonly int matrixWidth;
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
private readonly int startingOffset;
/// <summary>
/// The diffusion matrix
/// The diffusion matrix.
/// </summary>
private readonly DenseMatrix<float> matrix;

119
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs

@ -1,27 +1,17 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Effects
{
/// <summary>
/// Applies oil painting effect processing to the image.
/// Defines an oil painting effect.
/// </summary>
/// <remarks>Adapted from <see href="https://softwarebydefault.com/2013/06/29/oil-painting-cartoon-filter/"/> by Dewald Esterhuizen.</remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class OilPaintingProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class OilPaintingProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="OilPaintingProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="OilPaintingProcessor"/> class.
/// </summary>
/// <param name="levels">
/// The number of intensity levels. Higher values result in a broader range of color intensities forming part of the result image.
@ -39,111 +29,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
}
/// <summary>
/// Gets the intensity levels
/// Gets the number of intensity levels.
/// </summary>
public int Levels { get; }
/// <summary>
/// Gets the brush size
/// Gets the brush size.
/// </summary>
public int BrushSize { get; }
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(this.BrushSize));
}
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int maxY = endY - 1;
int maxX = endX - 1;
int radius = this.BrushSize >> 1;
int levels = this.Levels;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
source.CopyTo(targetPixels);
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
Span<TPixel> targetRow = targetPixels.GetRowSpan(y);
for (int x = startX; x < endX; x++)
{
int maxIntensity = 0;
int maxIndex = 0;
int[] intensityBin = new int[levels];
float[] redBin = new float[levels];
float[] blueBin = new float[levels];
float[] greenBin = new float[levels];
for (int fy = 0; fy <= radius; fy++)
{
int fyr = fy - radius;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);
for (int fx = 0; fx <= radius; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
var vector = sourceOffsetRow[offsetX].ToVector4();
float sourceRed = vector.X;
float sourceBlue = vector.Z;
float sourceGreen = vector.Y;
int currentIntensity = (int)MathF.Round(
(sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));
intensityBin[currentIntensity]++;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
if (intensityBin[currentIntensity] > maxIntensity)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
}
}
float red = MathF.Abs(redBin[maxIndex] / maxIntensity);
float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity);
ref TPixel pixel = ref targetRow[x];
pixel.FromVector4(
new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
}
}
}
});
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
return new OilPaintingProcessor<TPixel>(this);
}
}
}

129
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs

@ -0,0 +1,129 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Effects
{
/// <summary>
/// Applies oil painting effect processing to the image.
/// </summary>
/// <remarks>Adapted from <see href="https://softwarebydefault.com/2013/06/29/oil-painting-cartoon-filter/"/> by Dewald Esterhuizen.</remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class OilPaintingProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly OilPaintingProcessor definition;
public OilPaintingProcessor(OilPaintingProcessor definition)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
int brushSize = this.definition.BrushSize;
if (brushSize <= 0 || brushSize > source.Height || brushSize > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(brushSize));
}
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int maxY = endY - 1;
int maxX = endX - 1;
int radius = brushSize >> 1;
int levels = this.definition.Levels;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
source.CopyTo(targetPixels);
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
Span<TPixel> targetRow = targetPixels.GetRowSpan(y);
for (int x = startX; x < endX; x++)
{
int maxIntensity = 0;
int maxIndex = 0;
int[] intensityBin = new int[levels];
float[] redBin = new float[levels];
float[] blueBin = new float[levels];
float[] greenBin = new float[levels];
for (int fy = 0; fy <= radius; fy++)
{
int fyr = fy - radius;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);
for (int fx = 0; fx <= radius; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
var vector = sourceOffsetRow[offsetX].ToVector4();
float sourceRed = vector.X;
float sourceBlue = vector.Z;
float sourceGreen = vector.Y;
int currentIntensity = (int)MathF.Round(
(sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));
intensityBin[currentIntensity]++;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
if (intensityBin[currentIntensity] > maxIntensity)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
}
}
float red = MathF.Abs(redBin[maxIndex] / maxIntensity);
float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity);
ref TPixel pixel = ref targetRow[x];
pixel.FromVector4(
new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
}
}
}
});
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}
}

91
src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs

@ -1,25 +1,17 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Common;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Effects
{
/// <summary>
/// Applies a pixelation effect processing to the image.
/// Defines a pixelation effect of a given size.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class PixelateProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class PixelateProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="PixelateProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="PixelateProcessor"/> class.
/// </summary>
/// <param name="size">The size of the pixels. Must be greater than 0.</param>
/// <exception cref="System.ArgumentException">
@ -36,80 +28,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
/// </summary>
public int Size { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(this.Size));
}
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int size = this.Size;
int offset = this.Size / 2;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
// Get the range on the y-plane to choose from.
IEnumerable<int> range = EnumerableExtensions.SteppedRange(minY, i => i < maxY, size);
Parallel.ForEach(
range,
configuration.GetParallelOptions(),
y =>
{
int offsetY = y - startY;
int offsetPy = offset;
// Make sure that the offset is within the boundary of the image.
while (offsetY + offsetPy >= maxY)
{
offsetPy--;
}
Span<TPixel> row = source.GetPixelRowSpan(offsetY + offsetPy);
for (int x = minX; x < maxX; x += size)
{
int offsetX = x - startX;
int offsetPx = offset;
while (x + offsetPx >= maxX)
{
offsetPx--;
}
// Get the pixel color in the centre of the soon to be pixelated area.
TPixel pixel = row[offsetX + offsetPx];
// For each pixel in the pixelate size, set it to the centre color.
for (int l = offsetY; l < offsetY + size && l < maxY; l++)
{
for (int k = offsetX; k < offsetX + size && k < maxX; k++)
{
source[k, l] = pixel;
}
}
}
});
return new PixelateProcessor<TPixel>(this);
}
}
}

111
src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs

@ -0,0 +1,111 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Common;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Effects
{
/// <summary>
/// Applies a pixelation effect processing to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class PixelateProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PixelateProcessor definition;
/// <summary>
/// Initializes a new instance of the <see cref="PixelateProcessor{TPixel}"/> class.
/// </summary>
/// <param name="definition">The <see cref="PixelateProcessor"/>.</param>
public PixelateProcessor(PixelateProcessor definition)
{
this.definition = definition;
}
private int Size => this.definition.Size;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(this.Size));
}
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int size = this.Size;
int offset = this.Size / 2;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
// Get the range on the y-plane to choose from.
IEnumerable<int> range = EnumerableExtensions.SteppedRange(minY, i => i < maxY, size);
Parallel.ForEach(
range,
configuration.GetParallelOptions(),
y =>
{
int offsetY = y - startY;
int offsetPy = offset;
// Make sure that the offset is within the boundary of the image.
while (offsetY + offsetPy >= maxY)
{
offsetPy--;
}
Span<TPixel> row = source.GetPixelRowSpan(offsetY + offsetPy);
for (int x = minX; x < maxX; x += size)
{
int offsetX = x - startX;
int offsetPx = offset;
while (x + offsetPx >= maxX)
{
offsetPx--;
}
// Get the pixel color in the centre of the soon to be pixelated area.
TPixel pixel = row[offsetX + offsetPx];
// For each pixel in the pixelate size, set it to the centre color.
for (int l = offsetY; l < offsetY + size && l < maxY; l++)
{
for (int k = offsetX; k < offsetX + size && k < maxX; k++)
{
source[k, l] = pixel;
}
}
}
});
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save