diff --git a/ImageSharp.sln b/ImageSharp.sln index afc7dce81..e949d1d57 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -21,6 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt features.md = features.md global.json = global.json ImageSharp.ruleset = ImageSharp.ruleset + ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings NuGet.config = NuGet.config build\package.json = build\package.json README.md = README.md diff --git a/Settings.StyleCop b/Settings.StyleCop index b4cc1655f..2716e8d0a 100644 --- a/Settings.StyleCop +++ b/Settings.StyleCop @@ -39,6 +39,7 @@ desensitivity premultiplied endianness + thresholding diff --git a/src/ImageSharp/Bootstrapper.cs b/src/ImageSharp/Configuration.cs similarity index 54% rename from src/ImageSharp/Bootstrapper.cs rename to src/ImageSharp/Configuration.cs index d970f6e55..013c13495 100644 --- a/src/ImageSharp/Bootstrapper.cs +++ b/src/ImageSharp/Configuration.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -16,54 +16,48 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public static class Bootstrapper + public class Configuration { /// - /// The list of supported . + /// A lazily initialized configuration default instance. /// - private static readonly List ImageFormatsList; + private static readonly Lazy Lazy = new Lazy(() => new Configuration()); /// - /// An object that can be used to synchronize access to the . + /// An object that can be used to synchronize access to the . /// private static readonly object SyncRoot = new object(); /// - /// Initializes static members of the class. + /// The list of supported . /// - static Bootstrapper() - { - ImageFormatsList = new List - { - new BmpFormat(), - new JpegFormat(), - new PngFormat(), - new GifFormat() - }; - SetMaxHeaderSize(); - ParallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; - } + private readonly List imageFormatsList = new List(); + + /// + /// Gets the default instance. + /// + public static Configuration Default { get; } = Lazy.Value; /// /// Gets the collection of supported /// - public static IReadOnlyCollection ImageFormats => new ReadOnlyCollection(ImageFormatsList); + public IReadOnlyCollection ImageFormats => new ReadOnlyCollection(this.imageFormatsList); /// /// Gets the global parallel options for processing tasks in parallel. /// - public static ParallelOptions ParallelOptions { get; } + public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; /// /// Gets the maximum header size of all formats. /// - internal static int MaxHeaderSize { get; private set; } + internal int MaxHeaderSize { get; private set; } /// /// Adds a new to the collection of supported image formats. /// /// The new format to add. - public static void AddImageFormat(IImageFormat format) + public void AddImageFormat(IImageFormat format) { Guard.NotNull(format, nameof(format)); Guard.NotNull(format.Encoder, nameof(format), "The encoder should not be null."); @@ -72,50 +66,72 @@ namespace ImageSharp Guard.NotNullOrEmpty(format.Extension, nameof(format), "The extension should not be null or empty."); Guard.NotNullOrEmpty(format.SupportedExtensions, nameof(format), "The supported extensions not be null or empty."); - AddImageFormatLocked(format); + this.AddImageFormatLocked(format); } - private static void AddImageFormatLocked(IImageFormat format) + /// + /// Adds image format. The class is locked to make it thread safe. + /// + /// The image format. + private void AddImageFormatLocked(IImageFormat format) { lock (SyncRoot) { - GuardDuplicate(format); - - ImageFormatsList.Add(format); + if (this.GuardDuplicate(format)) + { + this.imageFormatsList.Add(format); - SetMaxHeaderSize(); + this.SetMaxHeaderSize(); + } } } - private static void GuardDuplicate(IImageFormat format) + /// + /// Checks to ensure duplicate image formats are not added. + /// + /// The image format. + /// Thrown if a duplicate is added. + /// + /// The . + /// + private bool GuardDuplicate(IImageFormat format) { if (!format.SupportedExtensions.Contains(format.Extension, StringComparer.OrdinalIgnoreCase)) { throw new ArgumentException("The supported extensions should contain the default extension.", nameof(format)); } + // ReSharper disable once ConvertClosureToMethodGroup + // Prevents method group allocation if (format.SupportedExtensions.Any(e => string.IsNullOrWhiteSpace(e))) { throw new ArgumentException("The supported extensions should not contain empty values.", nameof(format)); } - foreach (var imageFormat in ImageFormatsList) + // If there is already a format with the same extension or a format that supports that + // extension return false. + foreach (IImageFormat imageFormat in this.imageFormatsList) { if (imageFormat.Extension.Equals(format.Extension, StringComparison.OrdinalIgnoreCase)) { - throw new ArgumentException("There is already a format with the same extension.", nameof(format)); + return false; } if (imageFormat.SupportedExtensions.Intersect(format.SupportedExtensions, StringComparer.OrdinalIgnoreCase).Any()) { - throw new ArgumentException("There is already a format that supports the same extension.", nameof(format)); + return false; } } + + return true; } - private static void SetMaxHeaderSize() + /// + /// Sets max header size. + /// + private void SetMaxHeaderSize() { - MaxHeaderSize = ImageFormatsList.Max(x => x.HeaderSize); + this.MaxHeaderSize = this.imageFormatsList.Max(x => x.HeaderSize); } } } diff --git a/src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs index 05cc7b0dd..535635a45 100644 --- a/src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs +++ b/src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// Combines two images together by blending the pixels. /// /// The pixel format. - public class DrawImageProcessor : ImageFilteringProcessor + public class DrawImageProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs index dab0baa5a..a472b6fe6 100644 --- a/src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs @@ -20,8 +20,8 @@ namespace ImageSharp.Drawing.Processors /// Draws a path using the processor pipeline /// /// The type of the color. - /// - public class DrawPathProcessor : ImageFilteringProcessor + /// + public class DrawPathProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { private const float AntialiasFactor = 1f; diff --git a/src/ImageSharp/Drawing/Processors/FillProcessor.cs b/src/ImageSharp/Drawing/Processors/FillProcessor.cs index a2cf12fdd..9a44fc2ab 100644 --- a/src/ImageSharp/Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp/Drawing/Processors/FillProcessor.cs @@ -16,7 +16,7 @@ namespace ImageSharp.Drawing.Processors /// Using the bursh as a source of pixels colors blends the brush color with source. /// /// The pixel format. - public class FillProcessor : ImageFilteringProcessor + public class FillProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Drawing/Processors/FillShapeProcessor.cs b/src/ImageSharp/Drawing/Processors/FillShapeProcessor.cs index 7da2e041a..078cffe34 100644 --- a/src/ImageSharp/Drawing/Processors/FillShapeProcessor.cs +++ b/src/ImageSharp/Drawing/Processors/FillShapeProcessor.cs @@ -17,8 +17,8 @@ namespace ImageSharp.Drawing.Processors /// Usinf a brsuh and a shape fills shape with contents of brush the /// /// The type of the color. - /// - public class FillShapeProcessor : ImageFilteringProcessor + /// + public class FillShapeProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { private const float AntialiasFactor = 1f; diff --git a/src/ImageSharp/Filters/ColorMatrix/ColorBlindness.cs b/src/ImageSharp/Filters/ColorMatrix/ColorBlindness.cs index bb30492a7..d0c61bd73 100644 --- a/src/ImageSharp/Filters/ColorMatrix/ColorBlindness.cs +++ b/src/ImageSharp/Filters/ColorMatrix/ColorBlindness.cs @@ -40,7 +40,7 @@ namespace ImageSharp public static Image ColorBlindness(this Image source, ColorBlindness colorBlindness, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - IImageFilteringProcessor processor; + IImageProcessor processor; switch (colorBlindness) { diff --git a/src/ImageSharp/Filters/ColorMatrix/Grayscale.cs b/src/ImageSharp/Filters/ColorMatrix/Grayscale.cs index fa024a852..d98ce27b9 100644 --- a/src/ImageSharp/Filters/ColorMatrix/Grayscale.cs +++ b/src/ImageSharp/Filters/ColorMatrix/Grayscale.cs @@ -40,8 +40,8 @@ namespace ImageSharp public static Image Grayscale(this Image source, Rectangle rectangle, GrayscaleMode mode = GrayscaleMode.Bt709) where TColor : struct, IPackedPixel, IEquatable { - IImageFilteringProcessor processor = mode == GrayscaleMode.Bt709 - ? (IImageFilteringProcessor)new GrayscaleBt709Processor() + IImageProcessor processor = mode == GrayscaleMode.Bt709 + ? (IImageProcessor)new GrayscaleBt709Processor() : new GrayscaleBt601Processor(); return source.Process(rectangle, processor); diff --git a/src/ImageSharp/Filters/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Filters/Processors/Binarization/BinaryThresholdProcessor.cs index baf9c36ca..8a042c359 100644 --- a/src/ImageSharp/Filters/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Binarization/BinaryThresholdProcessor.cs @@ -9,11 +9,11 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to perform binary threshold filtering against an + /// An to perform binary threshold filtering against an /// . The image will be converted to grayscale before thresholding occurs. /// /// The pixel format. - public class BinaryThresholdProcessor : ImageFilteringProcessor + public class BinaryThresholdProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs b/src/ImageSharp/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs index a3e54cdbb..67f9525f7 100644 --- a/src/ImageSharp/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs +++ b/src/ImageSharp/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// The color matrix filter. Inherit from this class to perform operation involving color matrices. /// /// The pixel format. - public abstract class ColorMatrixFilter : ImageFilteringProcessor, IColorMatrixFilter + public abstract class ColorMatrixFilter : ImageProcessor, IColorMatrixFilter where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs b/src/ImageSharp/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs index 9fcda4b95..295a0d972 100644 --- a/src/ImageSharp/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs +++ b/src/ImageSharp/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// alter the image pixels. /// /// The pixel format. - public interface IColorMatrixFilter : IImageFilteringProcessor + public interface IColorMatrixFilter : IImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/BoxBlurProcessor.cs index 7780992bb..98ab075f1 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/BoxBlurProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Processors /// Applies a Box blur sampler to the image. /// /// The pixel format. - public class BoxBlurProcessor : ImageFilteringProcessor + public class BoxBlurProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/Convolution2DProcessor.cs index e00495302..9db67f062 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/Convolution2DProcessor.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// Defines a sampler that uses two one-dimensional matrices to perform convolution against an image. /// /// The pixel format. - public class Convolution2DProcessor : ImageFilteringProcessor + public class Convolution2DProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/Convolution2PassProcessor.cs index f90440293..80e3c6f92 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/Convolution2PassProcessor.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// Defines a sampler that uses two one-dimensional matrices to perform two-pass convolution against an image. /// /// The pixel format. - public class Convolution2PassProcessor : ImageFilteringProcessor + public class Convolution2PassProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/ConvolutionProcessor.cs index e4d3f4d42..b771cc562 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/ConvolutionProcessor.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// Defines a sampler that uses a 2 dimensional matrix to perform convolution against an image. /// /// The pixel format. - public class ConvolutionProcessor : ImageFilteringProcessor + public class ConvolutionProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs index 446771c26..40cdd2052 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Processors /// Defines a sampler that detects edges within an image using two one-dimensional matrices. /// /// The pixel format. - public abstract class EdgeDetector2DProcessor : ImageFilteringProcessor, IEdgeDetectorProcessor + public abstract class EdgeDetector2DProcessor : ImageProcessor, IEdgeDetectorProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs index b9f5e449e..a317c183d 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// Defines a sampler that detects edges within an image using a eight two dimensional matrices. /// /// The pixel format. - public abstract class EdgeDetectorCompassProcessor : ImageFilteringProcessor, IEdgeDetectorProcessor + public abstract class EdgeDetectorCompassProcessor : ImageProcessor, IEdgeDetectorProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs index 7542a3631..332b10e41 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Processors /// Defines a sampler that detects edges within an image using a single two dimensional matrix. /// /// The pixel format. - public abstract class EdgeDetectorProcessor : ImageFilteringProcessor, IEdgeDetectorProcessor + public abstract class EdgeDetectorProcessor : ImageProcessor, IEdgeDetectorProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs index f98fdf56b..f4b2442d0 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Processors /// Provides properties and methods allowing the detection of edges within an image. /// /// The pixel format. - public interface IEdgeDetectorProcessor : IImageFilteringProcessor, IEdgeDetectorProcessor + public interface IEdgeDetectorProcessor : IImageProcessor, IEdgeDetectorProcessor where TColor : struct, IPackedPixel, IEquatable { } diff --git a/src/ImageSharp/Filters/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/GaussianBlurProcessor.cs index 543fe26af..81fa3dce4 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/GaussianBlurProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Processors /// Applies a Gaussian blur sampler to the image. /// /// The pixel format. - public class GaussianBlurProcessor : ImageFilteringProcessor + public class GaussianBlurProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Filters/Processors/Convolution/GaussianSharpenProcessor.cs index e2e9b418b..5030085a0 100644 --- a/src/ImageSharp/Filters/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Convolution/GaussianSharpenProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Processors /// Applies a Gaussian sharpening sampler to the image. /// /// The pixel format. - public class GaussianSharpenProcessor : ImageFilteringProcessor + public class GaussianSharpenProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/AlphaProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/AlphaProcessor.cs index 0e9406ee5..59c935280 100644 --- a/src/ImageSharp/Filters/Processors/Effects/AlphaProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/AlphaProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to change the alpha component of an . + /// An to change the alpha component of an . /// /// The pixel format. - public class AlphaProcessor : ImageFilteringProcessor + public class AlphaProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs index ab6fa2424..3e8ea5417 100644 --- a/src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Processors /// Sets the background color of the image. /// /// The pixel format. - public class BackgroundColorProcessor : ImageFilteringProcessor + public class BackgroundColorProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/BrightnessProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/BrightnessProcessor.cs index 8bc021618..70c6bd6b0 100644 --- a/src/ImageSharp/Filters/Processors/Effects/BrightnessProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/BrightnessProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to change the brightness of an . + /// An to change the brightness of an . /// /// The pixel format. - public class BrightnessProcessor : ImageFilteringProcessor + public class BrightnessProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/ContrastProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/ContrastProcessor.cs index ba830b12a..00c5d441a 100644 --- a/src/ImageSharp/Filters/Processors/Effects/ContrastProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/ContrastProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to change the contrast of an . + /// An to change the contrast of an . /// /// The pixel format. - public class ContrastProcessor : ImageFilteringProcessor + public class ContrastProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/InvertProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/InvertProcessor.cs index e34d15f05..7ceb11194 100644 --- a/src/ImageSharp/Filters/Processors/Effects/InvertProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/InvertProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to invert the colors of an . + /// An to invert the colors of an . /// /// The pixel format. - public class InvertProcessor : ImageFilteringProcessor + public class InvertProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/OilPaintingProcessor.cs index b0c886acf..7cbcafaba 100644 --- a/src/ImageSharp/Filters/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/OilPaintingProcessor.cs @@ -10,11 +10,11 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to apply an oil painting effect to an . + /// An to apply an oil painting effect to an . /// /// Adapted from by Dewald Esterhuizen. /// The pixel format. - public class OilPaintingProcessor : ImageFilteringProcessor + public class OilPaintingProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Filters/Processors/Effects/PixelateProcessor.cs index a24df71aa..110cface2 100644 --- a/src/ImageSharp/Filters/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Effects/PixelateProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An to pixelate the colors of an . + /// An to pixelate the colors of an . /// /// The pixel format. - public class PixelateProcessor : ImageFilteringProcessor + public class PixelateProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/IImageFilteringProcessor.cs b/src/ImageSharp/Filters/Processors/IImageFilteringProcessor.cs deleted file mode 100644 index a121caa3a..000000000 --- a/src/ImageSharp/Filters/Processors/IImageFilteringProcessor.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Processors -{ - using System; - - /// - /// Encapsulates methods to alter the pixels of an image. The processor operates on the original source pixels. - /// - /// The pixel format. - public interface IImageFilteringProcessor : IImageProcessor - where TColor : struct, IPackedPixel, IEquatable - { - /// - /// Applies the process to the specified portion of the specified . - /// - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - /// - /// The method keeps the source image unchanged and returns the - /// the result of image processing filter as new image. - /// - /// - /// is null. - /// - /// - /// doesnt fit the dimension of the image. - /// - void Apply(ImageBase source, Rectangle sourceRectangle); - } -} diff --git a/src/ImageSharp/Filters/Processors/ImageFilteringProcessor.cs b/src/ImageSharp/Filters/Processors/ImageFilteringProcessor.cs deleted file mode 100644 index f61731651..000000000 --- a/src/ImageSharp/Filters/Processors/ImageFilteringProcessor.cs +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Processors -{ - using System; - - /// - /// Encapsulates methods to alter the pixels of an image. The processor operates on the original source pixels. - /// - /// The pixel format. - public abstract class ImageFilteringProcessor : ImageProcessor, IImageFilteringProcessor - where TColor : struct, IPackedPixel, IEquatable - { - /// - public void Apply(ImageBase source, Rectangle sourceRectangle) - { - try - { - this.BeforeApply(source, sourceRectangle); - - this.OnApply(source, sourceRectangle); - - this.AfterApply(source, sourceRectangle); - } - catch (Exception ex) - { - throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); - } - } - - /// - /// This method is called before the process is applied to prepare the processor. - /// - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void BeforeApply(ImageBase source, Rectangle sourceRectangle) - { - } - - /// - /// Applies the process to the specified portion of the specified at the specified location - /// and with the specified size. - /// - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected abstract void OnApply(ImageBase source, Rectangle sourceRectangle); - - /// - /// This method is called after the process is applied to prepare the processor. - /// - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void AfterApply(ImageBase source, Rectangle sourceRectangle) - { - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Filters/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Filters/Processors/Overlays/GlowProcessor.cs index 36a0b1a57..6e7d27929 100644 --- a/src/ImageSharp/Filters/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Overlays/GlowProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An that applies a radial glow effect an . + /// An that applies a radial glow effect an . /// /// The pixel format. - public class GlowProcessor : ImageFilteringProcessor + public class GlowProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Filters/Processors/Overlays/VignetteProcessor.cs index 318b9063a..ddb7b569f 100644 --- a/src/ImageSharp/Filters/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Overlays/VignetteProcessor.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Processors using System.Threading.Tasks; /// - /// An that applies a radial vignette effect to an . + /// An that applies a radial vignette effect to an . /// /// The pixel format. - public class VignetteProcessor : ImageFilteringProcessor + public class VignetteProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Filters/Processors/Transforms/CropProcessor.cs index a76897436..7efd9b924 100644 --- a/src/ImageSharp/Filters/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Transforms/CropProcessor.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Processors /// Provides methods to allow the cropping of an image. /// /// The pixel format. - public class CropProcessor : ImageFilteringProcessor + public class CropProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Filters/Processors/Transforms/EntropyCropProcessor.cs index a8bf373dc..78bef63b0 100644 --- a/src/ImageSharp/Filters/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Transforms/EntropyCropProcessor.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Processors /// entropy. /// /// The pixel format. - public class EntropyCropProcessor : ImageFilteringProcessor + public class EntropyCropProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Filters/Processors/Transforms/FlipProcessor.cs index aff49327a..4973c10d6 100644 --- a/src/ImageSharp/Filters/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Transforms/FlipProcessor.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Processors /// Provides methods that allow the flipping of an image around its center point. /// /// The pixel format. - public class FlipProcessor : ImageFilteringProcessor + public class FlipProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Transforms/Matrix3x2Processor.cs b/src/ImageSharp/Filters/Processors/Transforms/Matrix3x2Processor.cs index c9da4828a..b6f3d5a66 100644 --- a/src/ImageSharp/Filters/Processors/Transforms/Matrix3x2Processor.cs +++ b/src/ImageSharp/Filters/Processors/Transforms/Matrix3x2Processor.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Processors /// Provides methods to transform an image using a . /// /// The pixel format. - public abstract class Matrix3x2Processor : ImageFilteringProcessor + public abstract class Matrix3x2Processor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Filters/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Filters/Processors/Transforms/ResamplingWeightedProcessor.cs index 860485e6d..f29560835 100644 --- a/src/ImageSharp/Filters/Processors/Transforms/ResamplingWeightedProcessor.cs +++ b/src/ImageSharp/Filters/Processors/Transforms/ResamplingWeightedProcessor.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Processors /// Adapted from /// /// The pixel format. - public abstract class ResamplingWeightedProcessor : ImageFilteringProcessor + public abstract class ResamplingWeightedProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 4f28cdc80..de2e400fa 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Formats /// /// Encapsulates a supported image format, providing means to encode and decode an image. + /// Individual formats implements in this interface must be registered in the /// public interface IImageFormat { diff --git a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs index 0813a3331..6fbbc312f 100644 --- a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs @@ -687,7 +687,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.ParallelOptions, + image.Configuration.ParallelOptions, y => { int yoff = this.grayImage.GetRowOffset(y); @@ -723,7 +723,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.ParallelOptions, + image.Configuration.ParallelOptions, y => { // TODO: Simplify + optimize + share duplicate code across converter methods @@ -764,7 +764,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.ParallelOptions, + image.Configuration.ParallelOptions, y => { // TODO: Simplify + optimize + share duplicate code across converter methods diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index 22975a3c4..99c24139c 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -15,21 +15,17 @@ namespace ImageSharp [DebuggerDisplay("Image: {Width}x{Height}")] public class Image : Image { - /// - /// Initializes a new instance of the class. - /// - public Image() - { - } - /// /// Initializes a new instance of the class /// with the height and the width of the image. /// /// The width of the image in pixels. /// The height of the image in pixels. - public Image(int width, int height) - : base(width, height) + /// + /// The configuration providing initialization code which allows extending the library. + /// + public Image(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { } @@ -39,9 +35,12 @@ namespace ImageSharp /// /// The stream containing image information. /// + /// + /// The configuration providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(Stream stream) - : base(stream) + public Image(Stream stream, Configuration configuration = null) + : base(stream, configuration) { } @@ -51,9 +50,12 @@ namespace ImageSharp /// /// The byte array containing image information. /// + /// + /// The configuration providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(byte[] bytes) - : base(bytes) + public Image(byte[] bytes, Configuration configuration = null) + : base(bytes, configuration) { } diff --git a/src/ImageSharp/Image/IImageProcessor.cs b/src/ImageSharp/Image/IImageProcessor.cs index 145e83136..139596215 100644 --- a/src/ImageSharp/Image/IImageProcessor.cs +++ b/src/ImageSharp/Image/IImageProcessor.cs @@ -5,12 +5,15 @@ namespace ImageSharp.Processors { + using System; using System.Threading.Tasks; /// /// Encapsulates methods to alter the pixels of an image. /// - public interface IImageProcessor + /// The pixel format. + public interface IImageProcessor + where TColor : struct, IPackedPixel, IEquatable { /// /// Gets or sets the parallel options for processing tasks in parallel. @@ -22,5 +25,20 @@ namespace ImageSharp.Processors /// or expand individual pixel colors the value on processing. /// bool Compand { get; set; } + + /// + /// Applies the process to the specified portion of the specified . + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// + /// is null. + /// + /// + /// doesnt fit the dimension of the image. + /// + void Apply(ImageBase source, Rectangle sourceRectangle); } } diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 8fa40facc..8feaabdab 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -25,8 +25,12 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - protected ImageBase() + /// + /// The configuration providing initialization code which allows extending the library. + /// + protected ImageBase(Configuration configuration = null) { + this.Configuration = configuration ?? Configuration.Default; } /// @@ -34,11 +38,15 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. + /// + /// The configuration providing initialization code which allows extending the library. + /// /// /// Thrown if either or are less than or equal to 0. /// - protected ImageBase(int width, int height) + protected ImageBase(int width, int height, Configuration configuration = null) { + this.Configuration = configuration ?? Configuration.Default; this.InitPixels(width, height); } @@ -95,6 +103,11 @@ namespace ImageSharp /// public int FrameDelay { get; set; } + /// + /// Gets the configuration providing initialization code which allows extending the library. + /// + public Configuration Configuration { get; private set; } + /// public void InitPixels(int width, int height) { @@ -157,8 +170,9 @@ namespace ImageSharp /// protected void CopyProperties(ImageBase other) { + this.Configuration = other.Configuration; this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs index 4c67bd968..809eca1a4 100644 --- a/src/ImageSharp/Image/ImageFrame{TColor}.cs +++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs @@ -19,7 +19,13 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - public ImageFrame() + /// The width of the image in pixels. + /// The height of the image in pixels. + /// + /// The configuration providing initialization code which allows extending the library. + /// + public ImageFrame(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { } @@ -49,21 +55,19 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - ImageFrame target = new ImageFrame + ImageFrame target = new ImageFrame(this.Width, this.Height, this.Configuration) { Quality = this.Quality, FrameDelay = this.FrameDelay }; - target.InitPixels(this.Width, this.Height); - using (PixelAccessor pixels = this.Lock()) using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( 0, target.Height, - Bootstrapper.ParallelOptions, + this.Configuration.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) diff --git a/src/ImageSharp/Image/ImageProcessingExtensions.cs b/src/ImageSharp/Image/ImageProcessingExtensions.cs index 16ce455d2..68a3ab216 100644 --- a/src/ImageSharp/Image/ImageProcessingExtensions.cs +++ b/src/ImageSharp/Image/ImageProcessingExtensions.cs @@ -21,7 +21,7 @@ namespace ImageSharp /// The image this method extends. /// The processor to apply to the image. /// The . - internal static Image Process(this Image source, IImageFilteringProcessor processor) + internal static Image Process(this Image source, IImageProcessor processor) where TColor : struct, IPackedPixel, IEquatable { return Process(source, source.Bounds, processor); @@ -38,30 +38,17 @@ namespace ImageSharp /// /// The processors to apply to the image. /// The . - internal static Image Process(this Image source, Rectangle sourceRectangle, IImageFilteringProcessor processor) + internal static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor) where TColor : struct, IPackedPixel, IEquatable { - return PerformAction(source, (sourceImage) => processor.Apply(sourceImage, sourceRectangle)); - } - - /// - /// Performs the given action on the source image. - /// - /// The pixel format. - /// The image to perform the action against. - /// The to perform against the image. - /// The . - private static Image PerformAction(Image source, Action> action) - where TColor : struct, IPackedPixel, IEquatable - { - action(source); + processor.Apply(source, sourceRectangle); foreach (ImageFrame sourceFrame in source.Frames) { - action(sourceFrame); + processor.Apply(sourceFrame, sourceRectangle); } return source; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 63e73ed3e..ed556f2f3 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -37,24 +37,24 @@ namespace ImageSharp /// public const double DefaultVerticalResolution = 96; - /// - /// Initializes a new instance of the class. - /// - public Image() - { - this.CurrentImageFormat = Bootstrapper.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); - } - /// /// Initializes a new instance of the class /// with the height and the width of the image. /// /// The width of the image in pixels. /// The height of the image in pixels. - public Image(int width, int height) - : base(width, height) + /// + /// The configuration providing initialization code which allows extending the library. + /// + public Image(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { - this.CurrentImageFormat = Bootstrapper.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); + if (!this.Configuration.ImageFormats.Any()) + { + throw new NotSupportedException("No image formats have been configured."); + } + + this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } /// @@ -63,8 +63,12 @@ namespace ImageSharp /// /// The stream containing image information. /// + /// + /// The configuration providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(Stream stream) + public Image(Stream stream, Configuration configuration = null) + : base(configuration) { Guard.NotNull(stream, nameof(stream)); this.Load(stream); @@ -76,8 +80,12 @@ namespace ImageSharp /// /// The byte array containing image information. /// + /// + /// The configuration providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(byte[] bytes) + public Image(byte[] bytes, Configuration configuration = null) + : base(configuration) { Guard.NotNull(bytes, nameof(bytes)); @@ -293,7 +301,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - Image target = new Image(this.Width, this.Height) + Image target = new Image(this.Width, this.Height, this.Configuration) { Quality = this.Quality, FrameDelay = this.FrameDelay, @@ -309,7 +317,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - Bootstrapper.ParallelOptions, + this.Configuration.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) @@ -373,9 +381,9 @@ namespace ImageSharp /// private void Load(Stream stream) { - if (!Bootstrapper.ImageFormats.Any()) + if (!this.Configuration.ImageFormats.Any()) { - return; + throw new NotSupportedException("No image formats have been configured."); } if (!stream.CanRead) @@ -408,7 +416,7 @@ namespace ImageSharp StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); - foreach (IImageFormat format in Bootstrapper.ImageFormats) + foreach (IImageFormat format in this.Configuration.ImageFormats) { stringBuilder.AppendLine("-" + format); } @@ -425,20 +433,20 @@ namespace ImageSharp /// private bool Decode(Stream stream) { - int maxHeaderSize = Bootstrapper.MaxHeaderSize; + int maxHeaderSize = this.Configuration.MaxHeaderSize; if (maxHeaderSize <= 0) { return false; } - IImageFormat format = null; + IImageFormat format; byte[] header = ArrayPool.Shared.Rent(maxHeaderSize); try { long startPosition = stream.Position; stream.Read(header, 0, maxHeaderSize); stream.Position = startPosition; - format = Bootstrapper.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); + format = this.Configuration.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); } finally { @@ -455,4 +463,4 @@ namespace ImageSharp return true; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index 991be5aec..b4f02c7be 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -9,6 +9,7 @@ namespace ImageSharp using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using System.Threading.Tasks; /// /// Provides per-pixel access to generic pixels. @@ -60,6 +61,7 @@ namespace ImageSharp this.pixelsBase = (byte*)this.dataPointer.ToPointer(); this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; + this.ParallelOptions = image.Configuration.ParallelOptions; } /// @@ -86,6 +88,7 @@ namespace ImageSharp this.pixelsBase = (byte*)this.dataPointer.ToPointer(); this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; + this.ParallelOptions = Configuration.Default.ParallelOptions; } /// @@ -121,6 +124,11 @@ namespace ImageSharp /// public int Height { get; } + /// + /// Gets the global parallel options for processing tasks in parallel. + /// + public ParallelOptions ParallelOptions { get; } + /// /// Gets or sets the pixel at the specified position. /// diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs index 3ce264f38..89f7b9ad5 100644 --- a/src/ImageSharp/ImageFrame.cs +++ b/src/ImageSharp/ImageFrame.cs @@ -16,7 +16,13 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - public ImageFrame() + /// The width of the image in pixels. + /// The height of the image in pixels. + /// + /// The configuration providing initialization code which allows extending the library. + /// + public ImageFrame(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { } diff --git a/src/ImageSharp/ImageProcessor.cs b/src/ImageSharp/ImageProcessor.cs index 46fcb574d..49b60b678 100644 --- a/src/ImageSharp/ImageProcessor.cs +++ b/src/ImageSharp/ImageProcessor.cs @@ -12,13 +12,67 @@ namespace ImageSharp.Processors /// Allows the application of processors to images. /// /// The pixel format. - public abstract class ImageProcessor : IImageProcessor + public abstract class ImageProcessor : IImageProcessor where TColor : struct, IPackedPixel, IEquatable { /// - public virtual ParallelOptions ParallelOptions { get; set; } = Bootstrapper.ParallelOptions; + public virtual ParallelOptions ParallelOptions { get; set; } /// public virtual bool Compand { get; set; } = false; + + /// + public void Apply(ImageBase source, Rectangle sourceRectangle) + { + if (this.ParallelOptions == null) + { + this.ParallelOptions = source.Configuration.ParallelOptions; + } + + try + { + this.BeforeApply(source, sourceRectangle); + + this.OnApply(source, sourceRectangle); + + this.AfterApply(source, sourceRectangle); + } + catch (Exception ex) + { + throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); + } + } + + /// + /// This method is called before the process is applied to prepare the processor. + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void BeforeApply(ImageBase source, Rectangle sourceRectangle) + { + } + + /// + /// Applies the process to the specified portion of the specified at the specified location + /// and with the specified size. + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected abstract void OnApply(ImageBase source, Rectangle sourceRectangle); + + /// + /// This method is called after the process is applied to prepare the processor. + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void AfterApply(ImageBase source, Rectangle sourceRectangle) + { + } } } \ No newline at end of file diff --git a/src/ImageSharp/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index f060f18b9..7a42090c7 100644 --- a/src/ImageSharp/Quantizers/Quantize.cs +++ b/src/ImageSharp/Quantizers/Quantize.cs @@ -6,6 +6,7 @@ namespace ImageSharp { using System; + using System.Threading.Tasks; using ImageSharp.Quantizers; @@ -55,9 +56,24 @@ namespace ImageSharp public static Image Quantize(this Image source, IQuantizer quantizer, int maxColors) where TColor : struct, IPackedPixel, IEquatable { - QuantizedImage quantizedImage = quantizer.Quantize(source, maxColors); - source.SetPixels(source.Width, source.Height, quantizedImage.ToImage().Pixels); + QuantizedImage quantized = quantizer.Quantize(source, maxColors); + + int pixelCount = quantized.Pixels.Length; + int palleteCount = quantized.Palette.Length - 1; + TColor[] pixels = new TColor[pixelCount]; + + Parallel.For( + 0, + pixelCount, + source.Configuration.ParallelOptions, + i => + { + TColor color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])]; + pixels[i] = color; + }); + + source.SetPixels(source.Width, source.Height, pixels); return source; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Quantizers/QuantizedImage.cs b/src/ImageSharp/Quantizers/QuantizedImage.cs index 5ce53e71c..cc740f9be 100644 --- a/src/ImageSharp/Quantizers/QuantizedImage.cs +++ b/src/ImageSharp/Quantizers/QuantizedImage.cs @@ -59,33 +59,5 @@ namespace ImageSharp.Quantizers /// Gets the pixels of this . /// public byte[] Pixels { get; } - - /// - /// Converts this quantized image to a normal image. - /// - /// - /// The - /// - public Image ToImage() - { - Image image = new Image(); - - int pixelCount = this.Pixels.Length; - int palletCount = this.Palette.Length - 1; - TColor[] pixels = new TColor[pixelCount]; - - Parallel.For( - 0, - pixelCount, - Bootstrapper.ParallelOptions, - i => - { - TColor color = this.Palette[Math.Min(palletCount, this.Pixels[i])]; - pixels[i] = color; - }); - - image.SetPixels(this.Width, this.Height, pixels); - return image; - } } } \ No newline at end of file diff --git a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs index e235e68e8..55743f81e 100644 --- a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs +++ b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs @@ -773,7 +773,7 @@ namespace ImageSharp.Quantizers Parallel.For( 0, height, - Bootstrapper.ParallelOptions, + imagePixels.ParallelOptions, y => { byte[] rgba = ArrayPool.Shared.Rent(4); diff --git a/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs b/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs index 3c2b1b5d2..cddcc268d 100644 --- a/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs +++ b/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs @@ -25,7 +25,7 @@ namespace ImageSharp.Benchmarks.Image Parallel.For( 0, source.Height, - Bootstrapper.ParallelOptions, + Configuration.Default.ParallelOptions, y => { for (int x = 0; x < source.Width; x++) diff --git a/tests/ImageSharp.Tests/BootstrapperTests.cs b/tests/ImageSharp.Tests/BootstrapperTests.cs deleted file mode 100644 index b07fc01da..000000000 --- a/tests/ImageSharp.Tests/BootstrapperTests.cs +++ /dev/null @@ -1,164 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using System; - using System.Collections.Generic; - using ImageSharp.Formats; - using Xunit; - using System.Linq; - - public class BootstrapperTests - { - private class TestFormat : IImageFormat - { - private IImageDecoder decoder; - private IImageEncoder encoder; - private string mimeType; - private string extension; - private IEnumerable supportedExtensions; - - public TestFormat() - { - this.decoder = new JpegDecoder(); - this.encoder = new JpegEncoder(); - this.extension = "jpg"; - this.mimeType = "image/test"; - this.supportedExtensions = new string[] { "jpg" }; - } - - public IImageDecoder Decoder { get { return this.decoder; } set { this.decoder = value; } } - - public IImageEncoder Encoder { get { return this.encoder; } set { this.encoder = value; } } - - public string MimeType { get { return this.mimeType; } set { this.mimeType = value; } } - - public string Extension { get { return this.extension; } set { this.extension = value; } } - - public IEnumerable SupportedExtensions { get { return this.supportedExtensions; } set { this.supportedExtensions = value; } } - - public int HeaderSize { get { throw new NotImplementedException(); } } - - public bool IsSupportedFileFormat(byte[] header) { throw new NotImplementedException(); } - } - - [Fact] - public void AddImageFormatGuardNull() - { - ArgumentException exception; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(null); - }); - - var format = new TestFormat(); - format.Decoder = null; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("decoder", exception.Message); - - format = new TestFormat(); - format.Encoder = null; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("encoder", exception.Message); - - format = new TestFormat(); - format.MimeType = null; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("mime type", exception.Message); - - format = new TestFormat(); - format.MimeType = ""; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("mime type", exception.Message); - - format = new TestFormat(); - format.Extension = null; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("extension", exception.Message); - - format = new TestFormat(); - format.Extension = ""; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("extension", exception.Message); - - format = new TestFormat(); - format.SupportedExtensions = null; - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("supported extensions", exception.Message); - - format = new TestFormat(); - format.SupportedExtensions = Enumerable.Empty(); - - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("supported extensions", exception.Message); - } - - [Fact] - public void AddImageFormatChecks() - { - var format = new TestFormat(); - - var exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("format with the same", exception.Message); - - format.Extension = "test"; - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("should contain", exception.Message); - - format.SupportedExtensions = new string[] { "test", "jpg" }; - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("supports the same", exception.Message); - - format.SupportedExtensions = new string[] { "test", "" }; - exception = Assert.Throws(() => - { - Bootstrapper.AddImageFormat(format); - }); - Assert.Contains("empty values", exception.Message); - } - } -} diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs new file mode 100644 index 000000000..74a077341 --- /dev/null +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -0,0 +1,288 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using ImageSharp.Formats; + + using Xunit; + + /// + /// Tests the configuration class. + /// + public class ConfigurationTests + { + /// + /// Test that the default configuration is not null. + /// + [Fact] + public void TestDefultConfigurationIsNotNull() + { + Assert.True(Configuration.Default != null); + } + + /// + /// Test that the default configuration parallel options is not null. + /// + [Fact] + public void TestDefultConfigurationParallelOptionsIsNotNull() + { + Assert.True(Configuration.Default.ParallelOptions != null); + } + + /// + /// Test that the default configuration parallel options max degrees of parallelism matches the + /// environment processor count. + /// + [Fact] + public void TestDefultConfigurationMaxDegreeOfParallelism() + { + Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount); + } + + /// + /// Test that the default configuration parallel options is not null. + /// + [Fact] + public void TestDefultConfigurationImageFormatsIsNotNull() + { + Assert.True(Configuration.Default.ImageFormats != null); + } + + /// + /// Tests the method throws an exception + /// when the format is null. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullFormat() + { + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(null); + }); + } + + /// + /// Tests the method throws an exception + /// when the encoder is null. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullEncoder() + { + TestFormat format = new TestFormat { Encoder = null }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Tests the method throws an exception + /// when the decoder is null. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullDecoder() + { + TestFormat format = new TestFormat { Decoder = null }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Tests the method throws an exception + /// when the mime type is null or an empty string. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullOrEmptyMimeType() + { + TestFormat format = new TestFormat { MimeType = null }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + + format = new TestFormat { MimeType = string.Empty }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Tests the method throws an exception + /// when the extension is null or an empty string. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullOrEmptyExtension() + { + TestFormat format = new TestFormat { Extension = null }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + + format = new TestFormat { Extension = string.Empty }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Tests the method throws an exception + /// when the supported extensions list is null or empty. + /// + [Fact] + public void TestAddImageFormatThrowsWenSupportedExtensionsIsNullOrEmpty() + { + TestFormat format = new TestFormat { SupportedExtensions = null }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + + format = new TestFormat { SupportedExtensions = Enumerable.Empty() }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Tests the method throws an exception + /// when the supported extensions list does not contain the default extension. + /// + [Fact] + public void TestAddImageFormatThrowsWithoutDefaultExtension() + { + TestFormat format = new TestFormat { Extension = "test" }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Tests the method throws an exception + /// when the supported extensions list contains an empty string. + /// + [Fact] + public void TestAddImageFormatThrowsWithEmptySupportedExtension() + { + TestFormat format = new TestFormat + { + Extension = "test", + SupportedExtensions = new[] { "test", string.Empty } + }; + + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); + } + + /// + /// Test that the method ignores adding duplicate image formats. + /// + [Fact] + public void TestConfigurationIgnoresDuplicateImageFormats() + { + Configuration.Default.AddImageFormat(new PngFormat()); + Configuration.Default.AddImageFormat(new PngFormat()); + + Assert.True(Configuration.Default.ImageFormats.Count(i => i.GetType() == typeof(PngFormat)) == 1); + } + + /// + /// Test that the default image constructors use default configuration. + /// + [Fact] + public void TestImageUsesDefaultConfiguration() + { + Configuration.Default.AddImageFormat(new PngFormat()); + + Image image = new Image(1, 1); + Assert.Equal(image.Configuration.ParallelOptions, Configuration.Default.ParallelOptions); + Assert.Equal(image.Configuration.ImageFormats, Configuration.Default.ImageFormats); + } + + /// + /// Test that the default image constructor copies the configuration. + /// + [Fact] + public void TestImageCopiesConfiguration() + { + Configuration.Default.AddImageFormat(new PngFormat()); + + Image image = new Image(1, 1); + Image image2 = new Image(image); + Assert.Equal(image2.Configuration.ParallelOptions, image.Configuration.ParallelOptions); + Assert.True(image2.Configuration.ImageFormats.SequenceEqual(image.Configuration.ImageFormats)); + } + + /// + /// A test image format for testing the configuration. + /// + private class TestFormat : IImageFormat + { + /// + /// Initializes a new instance of the class. + /// + public TestFormat() + { + this.Decoder = new JpegDecoder(); + this.Encoder = new JpegEncoder(); + this.Extension = "jpg"; + this.MimeType = "image/test"; + this.SupportedExtensions = new[] { "jpg" }; + } + + /// + public IImageDecoder Decoder { get; set; } + + /// + public IImageEncoder Encoder { get; set; } + + /// + public string MimeType { get; set; } + + /// + public string Extension { get; set; } + + /// + public IEnumerable SupportedExtensions { get; set; } + + /// + public int HeaderSize + { + get + { + throw new NotImplementedException(); + } + } + + /// + public bool IsSupportedFileFormat(byte[] header) + { + throw new NotImplementedException(); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestBase.cs b/tests/ImageSharp.Tests/TestBase.cs index 91c7adef1..175bf215c 100644 --- a/tests/ImageSharp.Tests/TestBase.cs +++ b/tests/ImageSharp.Tests/TestBase.cs @@ -8,10 +8,18 @@ namespace ImageSharp.Tests using System.IO; /// - /// The test base class. + /// The test base class. Inherit from this class for any image manipulation tests. /// public abstract class TestBase { + /// + /// Creates the image output directory. + /// + /// The path. + /// The path parts. + /// + /// The . + /// protected string CreateOutputDirectory(string path, params string[] pathParts) { path = Path.Combine("TestOutput", path); diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 892e344d6..566796bf8 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -2,31 +2,56 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // + namespace ImageSharp.Tests { - using System; using System.Collections.Concurrent; using System.IO; + using ImageSharp.Formats; + + /// + /// A test image file. + /// public class TestFile { - private static readonly ConcurrentDictionary cache = new ConcurrentDictionary(); - private static readonly string FormatsDirectory = GetFormatsDirectory(); + /// + /// The test file cache. + /// + private static readonly ConcurrentDictionary Cache = new ConcurrentDictionary(); - private static string GetFormatsDirectory() - { - // Here for code coverage tests. - string directory = "TestImages/Formats/"; - if (Directory.Exists(directory)) - { - return directory; - } - return "../../../../TestImages/Formats/"; - } + /// + /// The formats directory. + /// + private static readonly string FormatsDirectory = GetFormatsDirectory(); + /// + /// The image. + /// private readonly Image image; + + /// + /// The file. + /// private readonly string file; + /// + /// Initializes static members of the class. + /// + static TestFile() + { + // Register the individual image formats. + // TODO: Is this the best place to do this? + Configuration.Default.AddImageFormat(new PngFormat()); + Configuration.Default.AddImageFormat(new JpegFormat()); + Configuration.Default.AddImageFormat(new BmpFormat()); + Configuration.Default.AddImageFormat(new GifFormat()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The file. private TestFile(string file) { this.file = file; @@ -35,50 +60,98 @@ namespace ImageSharp.Tests this.image = new Image(this.Bytes); } - public static string GetPath(string file) - { - return Path.Combine(FormatsDirectory, file); - } - - public static TestFile Create(string file) - { - return cache.GetOrAdd(file, (string fileName) => - { - return new TestFile(GetPath(file)); - }); - } - + /// + /// Gets the bytes. + /// public byte[] Bytes { get; } - public string FileName + /// + /// The file name. + /// + public string FileName => Path.GetFileName(this.file); + + /// + /// The file name without extension. + /// + public string FileNameWithoutExtension => Path.GetFileNameWithoutExtension(this.file); + + /// + /// Gets the full qualified path to the file. + /// + /// + /// The file path. + /// + /// + /// The . + /// + public static string GetPath(string file) { - get - { - return Path.GetFileName(this.file); - } + return Path.Combine(FormatsDirectory, file); } - public string FileNameWithoutExtension + /// + /// Creates a new test file or returns one from the cache. + /// + /// The file path. + /// + /// The . + /// + public static TestFile Create(string file) { - get - { - return Path.GetFileNameWithoutExtension(this.file); - } + return Cache.GetOrAdd(file, (string fileName) => new TestFile(GetPath(file))); } + /// + /// Gets the file name. + /// + /// The value. + /// + /// The . + /// public string GetFileName(object value) { - return this.FileNameWithoutExtension + "-" + value + Path.GetExtension(this.file); + return $"{this.FileNameWithoutExtension}-{value}{Path.GetExtension(this.file)}"; } + /// + /// Gets the file name without extension. + /// + /// The value. + /// + /// The . + /// public string GetFileNameWithoutExtension(object value) { return this.FileNameWithoutExtension + "-" + value; } + /// + /// Creates a new image. + /// + /// + /// The . + /// public Image CreateImage() { return new Image(this.image); } + + /// + /// Gets the correct path to the formats directory. + /// + /// + /// The . + /// + private static string GetFormatsDirectory() + { + // Here for code coverage tests. + string directory = "TestImages/Formats/"; + if (Directory.Exists(directory)) + { + return directory; + } + + return "../../../../TestImages/Formats/"; + } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index ad8cfe157..ea3645874 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -96,7 +96,7 @@ namespace ImageSharp.Tests private static IImageFormat GetImageFormatByExtension(string extension) { extension = extension.ToLower(); - return Bootstrapper.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); + return Configuration.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); } private string GetTestOutputDir() diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index 547efaa6f..489ef970a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -54,10 +54,10 @@ namespace ImageSharp.Tests /// Triggers instantiating the subclass of /// StandardImageClass = 1 << 29, - + // TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper // "All" is handled as a separate, individual case instead of using bitwise OR - All = 30 + All = 30 } } \ No newline at end of file