From 3718edb6e04b40733e33cb122db4499eeef614ab Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 16:22:09 +1100 Subject: [PATCH 01/10] Add ability to set custom Bootstrapper. This allows the setting of custom formats and parallel processing rules. --- ImageSharp.sln | 1 + Settings.StyleCop | 2 + src/ImageSharp/Bootstrapper.cs | 80 +++++++++++-------- src/ImageSharp/Formats/IImageFormat.cs | 1 + src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs | 6 +- src/ImageSharp/Image.cs | 27 +++++-- src/ImageSharp/Image/ImageBase{TColor}.cs | 20 ++++- src/ImageSharp/Image/ImageFrame{TColor}.cs | 10 ++- .../Image/ImageProcessingExtensions.cs | 5 ++ src/ImageSharp/Image/Image{TColor}.cs | 46 +++++++---- src/ImageSharp/ImageProcessor.cs | 2 +- src/ImageSharp/Quantizers/QuantizedImage.cs | 6 +- src/ImageSharp/Quantizers/Wu/WuQuantizer.cs | 2 +- .../ImageSharp.Benchmarks/Image/CopyPixels.cs | 2 +- tests/ImageSharp.Tests/BootstrapperTests.cs | 28 +++---- tests/ImageSharp.Tests/TestBase.cs | 24 +++++- .../TestUtilities/ImagingTestCaseUtility.cs | 2 +- 17 files changed, 179 insertions(+), 85 deletions(-) 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..737491cb1 100644 --- a/Settings.StyleCop +++ b/Settings.StyleCop @@ -39,6 +39,8 @@ desensitivity premultiplied endianness + bootstrapper + thresholding diff --git a/src/ImageSharp/Bootstrapper.cs b/src/ImageSharp/Bootstrapper.cs index d970f6e55..f44c6568c 100644 --- a/src/ImageSharp/Bootstrapper.cs +++ b/src/ImageSharp/Bootstrapper.cs @@ -16,12 +16,12 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public static class Bootstrapper + public class Bootstrapper { /// - /// The list of supported . + /// A lazily initialized bootstrapper default instance. /// - private static readonly List ImageFormatsList; + private static readonly Lazy Lazy = new Lazy(() => new Bootstrapper()); /// /// An object that can be used to synchronize access to the . @@ -29,41 +29,35 @@ namespace ImageSharp 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 Bootstrapper 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/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 4f28cdc80..ea2be7b29 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..981984333 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.Bootstrapper.ParallelOptions, y => { int yoff = this.grayImage.GetRowOffset(y); @@ -723,7 +723,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.ParallelOptions, + image.Bootstrapper.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.Bootstrapper.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..def8c575c 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -18,7 +18,11 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - public Image() + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// + public Image(Bootstrapper bootstrapper = null) + : base(bootstrapper) { } @@ -28,8 +32,11 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - public Image(int width, int height) - : base(width, height) + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// + public Image(int width, int height, Bootstrapper bootstrapper = null) + : base(width, height, bootstrapper) { } @@ -39,9 +46,12 @@ namespace ImageSharp /// /// The stream containing image information. /// + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(Stream stream) - : base(stream) + public Image(Stream stream, Bootstrapper bootstrapper = null) + : base(stream, bootstrapper) { } @@ -51,9 +61,12 @@ namespace ImageSharp /// /// The byte array containing image information. /// + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(byte[] bytes) - : base(bytes) + public Image(byte[] bytes, Bootstrapper bootstrapper = null) + : base(bytes, bootstrapper) { } diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 8fa40facc..4ac847d16 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 bootstrapper providing initialization code which allows extending the library. + /// + protected ImageBase(Bootstrapper bootstrapper = null) { + this.Bootstrapper = bootstrapper ?? Bootstrapper.Default; } /// @@ -34,11 +38,15 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. + /// + /// The bootstrapper 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, Bootstrapper bootstrapper = null) { + this.Bootstrapper = bootstrapper ?? Bootstrapper.Default; this.InitPixels(width, height); } @@ -95,6 +103,11 @@ namespace ImageSharp /// public int FrameDelay { get; set; } + /// + /// Gets the bootstrapper providing initialization code which allows extending the library. + /// + public Bootstrapper Bootstrapper { get; private set; } + /// public void InitPixels(int width, int height) { @@ -157,8 +170,9 @@ namespace ImageSharp /// protected void CopyProperties(ImageBase other) { + this.Bootstrapper = other.Bootstrapper; 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..fe064c244 100644 --- a/src/ImageSharp/Image/ImageFrame{TColor}.cs +++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs @@ -19,7 +19,11 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - public ImageFrame() + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// + public ImageFrame(Bootstrapper bootstrapper = null) + : base(bootstrapper) { } @@ -49,7 +53,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - ImageFrame target = new ImageFrame + ImageFrame target = new ImageFrame(this.Bootstrapper) { Quality = this.Quality, FrameDelay = this.FrameDelay @@ -63,7 +67,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - Bootstrapper.ParallelOptions, + this.Bootstrapper.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..0b6961b12 100644 --- a/src/ImageSharp/Image/ImageProcessingExtensions.cs +++ b/src/ImageSharp/Image/ImageProcessingExtensions.cs @@ -41,6 +41,11 @@ namespace ImageSharp internal static Image Process(this Image source, Rectangle sourceRectangle, IImageFilteringProcessor processor) where TColor : struct, IPackedPixel, IEquatable { + if (processor.ParallelOptions == null) + { + processor.ParallelOptions = source.Bootstrapper.ParallelOptions; + } + return PerformAction(source, (sourceImage) => processor.Apply(sourceImage, sourceRectangle)); } diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 63e73ed3e..c60585ab3 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -40,9 +40,14 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - public Image() + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// + public Image(Bootstrapper bootstrapper = null) + : base(bootstrapper) { - this.CurrentImageFormat = Bootstrapper.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); + // We want to throw here. + this.CurrentImageFormat = this.Bootstrapper.ImageFormats.First(); } /// @@ -51,10 +56,13 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - public Image(int width, int height) - : base(width, height) + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// + public Image(int width, int height, Bootstrapper bootstrapper = null) + : base(width, height, bootstrapper) { - this.CurrentImageFormat = Bootstrapper.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); + this.CurrentImageFormat = this.Bootstrapper.ImageFormats.First(); } /// @@ -63,8 +71,12 @@ namespace ImageSharp /// /// The stream containing image information. /// + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(Stream stream) + public Image(Stream stream, Bootstrapper bootstrapper = null) + : base(bootstrapper) { Guard.NotNull(stream, nameof(stream)); this.Load(stream); @@ -76,8 +88,12 @@ namespace ImageSharp /// /// The byte array containing image information. /// + /// + /// The bootstrapper providing initialization code which allows extending the library. + /// /// Thrown if the is null. - public Image(byte[] bytes) + public Image(byte[] bytes, Bootstrapper bootstrapper = null) + : base(bootstrapper) { Guard.NotNull(bytes, nameof(bytes)); @@ -293,7 +309,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - Image target = new Image(this.Width, this.Height) + Image target = new Image(this.Width, this.Height, this.Bootstrapper) { Quality = this.Quality, FrameDelay = this.FrameDelay, @@ -309,7 +325,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - Bootstrapper.ParallelOptions, + this.Bootstrapper.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) @@ -373,7 +389,7 @@ namespace ImageSharp /// private void Load(Stream stream) { - if (!Bootstrapper.ImageFormats.Any()) + if (!this.Bootstrapper.ImageFormats.Any()) { return; } @@ -408,7 +424,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.Bootstrapper.ImageFormats) { stringBuilder.AppendLine("-" + format); } @@ -425,20 +441,20 @@ namespace ImageSharp /// private bool Decode(Stream stream) { - int maxHeaderSize = Bootstrapper.MaxHeaderSize; + int maxHeaderSize = this.Bootstrapper.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.Bootstrapper.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); } finally { @@ -455,4 +471,4 @@ namespace ImageSharp return true; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/ImageProcessor.cs b/src/ImageSharp/ImageProcessor.cs index 46fcb574d..72d9f6b93 100644 --- a/src/ImageSharp/ImageProcessor.cs +++ b/src/ImageSharp/ImageProcessor.cs @@ -16,7 +16,7 @@ namespace ImageSharp.Processors 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; diff --git a/src/ImageSharp/Quantizers/QuantizedImage.cs b/src/ImageSharp/Quantizers/QuantizedImage.cs index 5ce53e71c..6b78ce801 100644 --- a/src/ImageSharp/Quantizers/QuantizedImage.cs +++ b/src/ImageSharp/Quantizers/QuantizedImage.cs @@ -71,16 +71,16 @@ namespace ImageSharp.Quantizers Image image = new Image(); int pixelCount = this.Pixels.Length; - int palletCount = this.Palette.Length - 1; + int palleteCount = this.Palette.Length - 1; TColor[] pixels = new TColor[pixelCount]; Parallel.For( 0, pixelCount, - Bootstrapper.ParallelOptions, + image.Bootstrapper.ParallelOptions, i => { - TColor color = this.Palette[Math.Min(palletCount, this.Pixels[i])]; + TColor color = this.Palette[Math.Min(palleteCount, this.Pixels[i])]; pixels[i] = color; }); diff --git a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs index e235e68e8..3035b1098 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, + Bootstrapper.Default.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..b17dc7aaf 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, + Bootstrapper.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 index b07fc01da..38d2c1150 100644 --- a/tests/ImageSharp.Tests/BootstrapperTests.cs +++ b/tests/ImageSharp.Tests/BootstrapperTests.cs @@ -52,7 +52,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(null); + Bootstrapper.Default.AddImageFormat(null); }); var format = new TestFormat(); @@ -60,7 +60,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("decoder", exception.Message); @@ -69,7 +69,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("encoder", exception.Message); @@ -78,7 +78,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("mime type", exception.Message); @@ -87,7 +87,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("mime type", exception.Message); @@ -96,7 +96,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("extension", exception.Message); @@ -105,7 +105,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("extension", exception.Message); @@ -114,7 +114,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("supported extensions", exception.Message); @@ -123,7 +123,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("supported extensions", exception.Message); } @@ -131,32 +131,32 @@ namespace ImageSharp.Tests [Fact] public void AddImageFormatChecks() { - var format = new TestFormat(); + TestFormat format = new TestFormat(); var exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("format with the same", exception.Message); format.Extension = "test"; exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("should contain", exception.Message); format.SupportedExtensions = new string[] { "test", "jpg" }; exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("supports the same", exception.Message); format.SupportedExtensions = new string[] { "test", "" }; exception = Assert.Throws(() => { - Bootstrapper.AddImageFormat(format); + Bootstrapper.Default.AddImageFormat(format); }); Assert.Contains("empty values", exception.Message); } diff --git a/tests/ImageSharp.Tests/TestBase.cs b/tests/ImageSharp.Tests/TestBase.cs index 91c7adef1..a7732972e 100644 --- a/tests/ImageSharp.Tests/TestBase.cs +++ b/tests/ImageSharp.Tests/TestBase.cs @@ -7,11 +7,33 @@ namespace ImageSharp.Tests { using System.IO; + using ImageSharp.Formats; + /// - /// The test base class. + /// The test base class. Inherit from this class for any image manipulation tests. /// public abstract class TestBase { + /// + /// Initializes a new instance of the class. + /// + protected TestBase() + { + // Register the individual image formats. + Bootstrapper.Default.AddImageFormat(new PngFormat()); + Bootstrapper.Default.AddImageFormat(new JpegFormat()); + Bootstrapper.Default.AddImageFormat(new BmpFormat()); + Bootstrapper.Default.AddImageFormat(new GifFormat()); + } + + /// + /// 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/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index ad8cfe157..5fc9f175e 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 Bootstrapper.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); } private string GetTestOutputDir() From f59de118ff72c5f15009f6fadfc9e4a008643250 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 18:39:10 +1100 Subject: [PATCH 02/10] Fix Tests Merge IImageFilteringProcessor with IImageProcessor to simplify encapsulation and allow easy setting of parallel options --- .../Drawing/Processors/DrawImageProcessor.cs | 2 +- .../Drawing/Processors/DrawPathProcessor.cs | 4 +- .../Drawing/Processors/FillProcessor.cs | 2 +- .../Drawing/Processors/FillShapeProcessor.cs | 4 +- .../Filters/ColorMatrix/ColorBlindness.cs | 2 +- .../Filters/ColorMatrix/Grayscale.cs | 4 +- .../Binarization/BinaryThresholdProcessor.cs | 4 +- .../ColorMatrix/ColorMatrixFilter.cs | 2 +- .../ColorMatrix/IColorMatrixFilter.cs | 2 +- .../Convolution/BoxBlurProcessor.cs | 2 +- .../Convolution/Convolution2DProcessor.cs | 2 +- .../Convolution/Convolution2PassProcessor.cs | 2 +- .../Convolution/ConvolutionProcessor.cs | 2 +- .../EdgeDetection/EdgeDetector2DProcessor.cs | 2 +- .../EdgeDetectorCompassProcessor.cs | 2 +- .../EdgeDetection/EdgeDetectorProcessor.cs | 2 +- .../EdgeDetection/IEdgeDetectorProcessor.cs | 2 +- .../Convolution/GaussianBlurProcessor.cs | 2 +- .../Convolution/GaussianSharpenProcessor.cs | 2 +- .../Processors/Effects/AlphaProcessor.cs | 4 +- .../Effects/BackgroundColorProcessor.cs | 2 +- .../Processors/Effects/BrightnessProcessor.cs | 4 +- .../Processors/Effects/ContrastProcessor.cs | 4 +- .../Processors/Effects/InvertProcessor.cs | 4 +- .../Effects/OilPaintingProcessor.cs | 4 +- .../Processors/Effects/PixelateProcessor.cs | 4 +- .../Processors/IImageFilteringProcessor.cs | 36 ---------- .../Processors/ImageFilteringProcessor.cs | 66 ------------------- .../Processors/Overlays/GlowProcessor.cs | 4 +- .../Processors/Overlays/VignetteProcessor.cs | 4 +- .../Processors/Transforms/CropProcessor.cs | 2 +- .../Transforms/EntropyCropProcessor.cs | 2 +- .../Processors/Transforms/FlipProcessor.cs | 2 +- .../Transforms/Matrix3x2Processor.cs | 2 +- .../Transforms/ResamplingWeightedProcessor.cs | 2 +- src/ImageSharp/Image/IImageProcessor.cs | 20 +++++- .../Image/ImageProcessingExtensions.cs | 9 +-- src/ImageSharp/ImageProcessor.cs | 56 +++++++++++++++- 38 files changed, 121 insertions(+), 156 deletions(-) delete mode 100644 src/ImageSharp/Filters/Processors/IImageFilteringProcessor.cs delete mode 100644 src/ImageSharp/Filters/Processors/ImageFilteringProcessor.cs 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/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/ImageProcessingExtensions.cs b/src/ImageSharp/Image/ImageProcessingExtensions.cs index 0b6961b12..3d33e73c4 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,14 +38,9 @@ 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 { - if (processor.ParallelOptions == null) - { - processor.ParallelOptions = source.Bootstrapper.ParallelOptions; - } - return PerformAction(source, (sourceImage) => processor.Apply(sourceImage, sourceRectangle)); } diff --git a/src/ImageSharp/ImageProcessor.cs b/src/ImageSharp/ImageProcessor.cs index 72d9f6b93..57c921893 100644 --- a/src/ImageSharp/ImageProcessor.cs +++ b/src/ImageSharp/ImageProcessor.cs @@ -12,7 +12,7 @@ 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 { /// @@ -20,5 +20,59 @@ namespace ImageSharp.Processors /// public virtual bool Compand { get; set; } = false; + + /// + public void Apply(ImageBase source, Rectangle sourceRectangle) + { + if (this.ParallelOptions == null) + { + this.ParallelOptions = source.Bootstrapper.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 From 2fc0d4b0e9a71d9e21d36d612e792cd8d9a6dfba Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 18:47:31 +1100 Subject: [PATCH 03/10] Fix bootstrapper test --- tests/ImageSharp.Tests/BootstrapperTests.cs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/tests/ImageSharp.Tests/BootstrapperTests.cs b/tests/ImageSharp.Tests/BootstrapperTests.cs index 38d2c1150..096b9f0d5 100644 --- a/tests/ImageSharp.Tests/BootstrapperTests.cs +++ b/tests/ImageSharp.Tests/BootstrapperTests.cs @@ -133,26 +133,13 @@ namespace ImageSharp.Tests { TestFormat format = new TestFormat(); - var exception = Assert.Throws(() => - { - Bootstrapper.Default.AddImageFormat(format); - }); - Assert.Contains("format with the same", exception.Message); - format.Extension = "test"; - exception = Assert.Throws(() => - { - Bootstrapper.Default.AddImageFormat(format); - }); + var exception = Assert.Throws(() => + { + Bootstrapper.Default.AddImageFormat(format); + }); Assert.Contains("should contain", exception.Message); - format.SupportedExtensions = new string[] { "test", "jpg" }; - exception = Assert.Throws(() => - { - Bootstrapper.Default.AddImageFormat(format); - }); - Assert.Contains("supports the same", exception.Message); - format.SupportedExtensions = new string[] { "test", "" }; exception = Assert.Throws(() => { From 0308ce77ed1883e8773445ca09bff1b08359cee0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 18:53:53 +1100 Subject: [PATCH 04/10] Simplify proecessing code --- .../Image/ImageProcessingExtensions.cs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Image/ImageProcessingExtensions.cs b/src/ImageSharp/Image/ImageProcessingExtensions.cs index 3d33e73c4..68a3ab216 100644 --- a/src/ImageSharp/Image/ImageProcessingExtensions.cs +++ b/src/ImageSharp/Image/ImageProcessingExtensions.cs @@ -41,27 +41,14 @@ namespace ImageSharp 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 From f237a31ef08d70a10c7256e793cf82f3705666f5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 20:41:00 +1100 Subject: [PATCH 05/10] Limit constructors, change test format loading --- src/ImageSharp/Image.cs | 11 ----------- src/ImageSharp/Image/ImageFrame{TColor}.cs | 10 +++++----- src/ImageSharp/Image/Image{TColor}.cs | 15 +-------------- src/ImageSharp/ImageFrame.cs | 8 +++++++- src/ImageSharp/Quantizers/QuantizedImage.cs | 2 +- tests/ImageSharp.Tests/TestBase.cs | 4 ++-- tests/ImageSharp.Tests/TestFile.cs | 2 +- .../ImageSharp.Tests/TestUtilities/PixelTypes.cs | 4 ++-- 8 files changed, 19 insertions(+), 37 deletions(-) diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index def8c575c..772cf6dbe 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -15,17 +15,6 @@ namespace ImageSharp [DebuggerDisplay("Image: {Width}x{Height}")] public class Image : Image { - /// - /// Initializes a new instance of the class. - /// - /// - /// The bootstrapper providing initialization code which allows extending the library. - /// - public Image(Bootstrapper bootstrapper = null) - : base(bootstrapper) - { - } - /// /// Initializes a new instance of the class /// with the height and the width of the image. diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs index fe064c244..aaf775ebb 100644 --- a/src/ImageSharp/Image/ImageFrame{TColor}.cs +++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs @@ -19,11 +19,13 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// + /// The width of the image in pixels. + /// The height of the image in pixels. /// /// The bootstrapper providing initialization code which allows extending the library. /// - public ImageFrame(Bootstrapper bootstrapper = null) - : base(bootstrapper) + public ImageFrame(int width, int height, Bootstrapper bootstrapper = null) + : base(width, height, bootstrapper) { } @@ -53,14 +55,12 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - ImageFrame target = new ImageFrame(this.Bootstrapper) + ImageFrame target = new ImageFrame(this.Width, this.Height, this.Bootstrapper) { Quality = this.Quality, FrameDelay = this.FrameDelay }; - target.InitPixels(this.Width, this.Height); - using (PixelAccessor pixels = this.Lock()) using (PixelAccessor targetPixels = target.Lock()) { diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index c60585ab3..84fb39a0c 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -37,19 +37,6 @@ namespace ImageSharp /// public const double DefaultVerticalResolution = 96; - /// - /// Initializes a new instance of the class. - /// - /// - /// The bootstrapper providing initialization code which allows extending the library. - /// - public Image(Bootstrapper bootstrapper = null) - : base(bootstrapper) - { - // We want to throw here. - this.CurrentImageFormat = this.Bootstrapper.ImageFormats.First(); - } - /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -391,7 +378,7 @@ namespace ImageSharp { if (!this.Bootstrapper.ImageFormats.Any()) { - return; + throw new NotSupportedException("No image formats have been configured."); } if (!stream.CanRead) diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs index 3ce264f38..66a2049e8 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 bootstrapper providing initialization code which allows extending the library. + /// + public ImageFrame(int width, int height, Bootstrapper bootstrapper = null) + : base(width, height, bootstrapper) { } diff --git a/src/ImageSharp/Quantizers/QuantizedImage.cs b/src/ImageSharp/Quantizers/QuantizedImage.cs index 6b78ce801..4f2c4b149 100644 --- a/src/ImageSharp/Quantizers/QuantizedImage.cs +++ b/src/ImageSharp/Quantizers/QuantizedImage.cs @@ -68,7 +68,7 @@ namespace ImageSharp.Quantizers /// public Image ToImage() { - Image image = new Image(); + Image image = new Image(this.Width, this.Height); int pixelCount = this.Pixels.Length; int palleteCount = this.Palette.Length - 1; diff --git a/tests/ImageSharp.Tests/TestBase.cs b/tests/ImageSharp.Tests/TestBase.cs index a7732972e..8a83746e7 100644 --- a/tests/ImageSharp.Tests/TestBase.cs +++ b/tests/ImageSharp.Tests/TestBase.cs @@ -15,9 +15,9 @@ namespace ImageSharp.Tests public abstract class TestBase { /// - /// Initializes a new instance of the class. + /// Initializes static members of the class. /// - protected TestBase() + static TestBase() { // Register the individual image formats. Bootstrapper.Default.AddImageFormat(new PngFormat()); diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 892e344d6..4237fdb51 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -39,7 +39,7 @@ namespace ImageSharp.Tests { return Path.Combine(FormatsDirectory, file); } - + public static TestFile Create(string file) { return cache.GetOrAdd(file, (string fileName) => 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 From baf1642d150b7faa68b1499f327846d4923b0ba7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 20:59:58 +1100 Subject: [PATCH 06/10] Move bootstrapper initializer --- tests/ImageSharp.Tests/TestBase.cs | 14 --- tests/ImageSharp.Tests/TestFile.cs | 145 ++++++++++++++++++++++------- 2 files changed, 109 insertions(+), 50 deletions(-) diff --git a/tests/ImageSharp.Tests/TestBase.cs b/tests/ImageSharp.Tests/TestBase.cs index 8a83746e7..175bf215c 100644 --- a/tests/ImageSharp.Tests/TestBase.cs +++ b/tests/ImageSharp.Tests/TestBase.cs @@ -7,25 +7,11 @@ namespace ImageSharp.Tests { using System.IO; - using ImageSharp.Formats; - /// /// The test base class. Inherit from this class for any image manipulation tests. /// public abstract class TestBase { - /// - /// Initializes static members of the class. - /// - static TestBase() - { - // Register the individual image formats. - Bootstrapper.Default.AddImageFormat(new PngFormat()); - Bootstrapper.Default.AddImageFormat(new JpegFormat()); - Bootstrapper.Default.AddImageFormat(new BmpFormat()); - Bootstrapper.Default.AddImageFormat(new GifFormat()); - } - /// /// Creates the image output directory. /// diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 4237fdb51..65f712f72 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? + Bootstrapper.Default.AddImageFormat(new PngFormat()); + Bootstrapper.Default.AddImageFormat(new JpegFormat()); + Bootstrapper.Default.AddImageFormat(new BmpFormat()); + Bootstrapper.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); - } + /// + /// Gets the bytes. + /// + public byte[] Bytes { get; } - public static TestFile Create(string file) - { - return cache.GetOrAdd(file, (string fileName) => - { - return new TestFile(GetPath(file)); - }); - } + /// + /// The file name. + /// + public string FileName => Path.GetFileName(this.file); - public byte[] Bytes { get; } + /// + /// The file name without extension. + /// + public string FileNameWithoutExtension => Path.GetFileNameWithoutExtension(this.file); - public string FileName + /// + /// 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/"; + } } } From 262026e4f756e876a693758f6f4019be428ff401 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Dec 2016 21:32:07 +1100 Subject: [PATCH 07/10] Use correct parallel options --- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 8 ++++++ src/ImageSharp/Quantizers/Quantize.cs | 22 +++++++++++++-- src/ImageSharp/Quantizers/QuantizedImage.cs | 28 ------------------- src/ImageSharp/Quantizers/Wu/WuQuantizer.cs | 2 +- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index 991be5aec..dc8c33dbe 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.Bootstrapper.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 = Bootstrapper.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/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index f060f18b9..b34398448 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.Bootstrapper.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 4f2c4b149..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(this.Width, this.Height); - - int pixelCount = this.Pixels.Length; - int palleteCount = this.Palette.Length - 1; - TColor[] pixels = new TColor[pixelCount]; - - Parallel.For( - 0, - pixelCount, - image.Bootstrapper.ParallelOptions, - i => - { - TColor color = this.Palette[Math.Min(palleteCount, 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 3035b1098..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.Default.ParallelOptions, + imagePixels.ParallelOptions, y => { byte[] rgba = ArrayPool.Shared.Rent(4); From ef60a6237e084d0609ac784de122fc746987bd05 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 31 Dec 2016 11:15:50 +1100 Subject: [PATCH 08/10] Rename Bootstrapper to Configuration --- Settings.StyleCop | 1 - .../{Bootstrapper.cs => Configuration.cs} | 14 +++---- src/ImageSharp/Formats/IImageFormat.cs | 2 +- src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs | 6 +-- src/ImageSharp/Image.cs | 24 ++++++------ src/ImageSharp/Image/ImageBase{TColor}.cs | 22 +++++------ src/ImageSharp/Image/ImageFrame{TColor}.cs | 12 +++--- src/ImageSharp/Image/Image{TColor}.cs | 38 +++++++++---------- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 4 +- src/ImageSharp/ImageFrame.cs | 8 ++-- src/ImageSharp/ImageProcessor.cs | 2 +- src/ImageSharp/Quantizers/Quantize.cs | 2 +- .../ImageSharp.Benchmarks/Image/CopyPixels.cs | 2 +- ...strapperTests.cs => ConfigurationTests.cs} | 26 ++++++------- tests/ImageSharp.Tests/TestFile.cs | 8 ++-- .../TestUtilities/ImagingTestCaseUtility.cs | 2 +- 16 files changed, 86 insertions(+), 87 deletions(-) rename src/ImageSharp/{Bootstrapper.cs => Configuration.cs} (91%) rename tests/ImageSharp.Tests/{BootstrapperTests.cs => ConfigurationTests.cs} (84%) diff --git a/Settings.StyleCop b/Settings.StyleCop index 737491cb1..2716e8d0a 100644 --- a/Settings.StyleCop +++ b/Settings.StyleCop @@ -39,7 +39,6 @@ desensitivity premultiplied endianness - bootstrapper thresholding diff --git a/src/ImageSharp/Bootstrapper.cs b/src/ImageSharp/Configuration.cs similarity index 91% rename from src/ImageSharp/Bootstrapper.cs rename to src/ImageSharp/Configuration.cs index f44c6568c..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,15 +16,15 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public class Bootstrapper + public class Configuration { /// - /// A lazily initialized bootstrapper default instance. + /// A lazily initialized configuration default instance. /// - private static readonly Lazy Lazy = new Lazy(() => new Bootstrapper()); + 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(); @@ -34,9 +34,9 @@ namespace ImageSharp private readonly List imageFormatsList = new List(); /// - /// Gets the default instance. + /// Gets the default instance. /// - public static Bootstrapper Default { get; } = Lazy.Value; + public static Configuration Default { get; } = Lazy.Value; /// /// Gets the collection of supported diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index ea2be7b29..de2e400fa 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -9,7 +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 + /// 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 981984333..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, - image.Bootstrapper.ParallelOptions, + image.Configuration.ParallelOptions, y => { int yoff = this.grayImage.GetRowOffset(y); @@ -723,7 +723,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - image.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, - image.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 772cf6dbe..99c24139c 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -21,11 +21,11 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// - public Image(int width, int height, Bootstrapper bootstrapper = null) - : base(width, height, bootstrapper) + public Image(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { } @@ -35,12 +35,12 @@ namespace ImageSharp /// /// The stream containing image information. /// - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(Stream stream, Bootstrapper bootstrapper = null) - : base(stream, bootstrapper) + public Image(Stream stream, Configuration configuration = null) + : base(stream, configuration) { } @@ -50,12 +50,12 @@ namespace ImageSharp /// /// The byte array containing image information. /// - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(byte[] bytes, Bootstrapper bootstrapper = null) - : base(bytes, bootstrapper) + public Image(byte[] bytes, Configuration configuration = null) + : base(bytes, configuration) { } diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 4ac847d16..8feaabdab 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -25,12 +25,12 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// - protected ImageBase(Bootstrapper bootstrapper = null) + protected ImageBase(Configuration configuration = null) { - this.Bootstrapper = bootstrapper ?? Bootstrapper.Default; + this.Configuration = configuration ?? Configuration.Default; } /// @@ -38,15 +38,15 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// 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, Bootstrapper bootstrapper = null) + protected ImageBase(int width, int height, Configuration configuration = null) { - this.Bootstrapper = bootstrapper ?? Bootstrapper.Default; + this.Configuration = configuration ?? Configuration.Default; this.InitPixels(width, height); } @@ -104,9 +104,9 @@ namespace ImageSharp public int FrameDelay { get; set; } /// - /// Gets the bootstrapper providing initialization code which allows extending the library. + /// Gets the configuration providing initialization code which allows extending the library. /// - public Bootstrapper Bootstrapper { get; private set; } + public Configuration Configuration { get; private set; } /// public void InitPixels(int width, int height) @@ -170,7 +170,7 @@ namespace ImageSharp /// protected void CopyProperties(ImageBase other) { - this.Bootstrapper = other.Bootstrapper; + this.Configuration = other.Configuration; this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; } diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs index aaf775ebb..809eca1a4 100644 --- a/src/ImageSharp/Image/ImageFrame{TColor}.cs +++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs @@ -21,11 +21,11 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// - public ImageFrame(int width, int height, Bootstrapper bootstrapper = null) - : base(width, height, bootstrapper) + public ImageFrame(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { } @@ -55,7 +55,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - ImageFrame target = new ImageFrame(this.Width, this.Height, this.Bootstrapper) + ImageFrame target = new ImageFrame(this.Width, this.Height, this.Configuration) { Quality = this.Quality, FrameDelay = this.FrameDelay @@ -67,7 +67,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - this.Bootstrapper.ParallelOptions, + this.Configuration.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 84fb39a0c..4d9511835 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -43,13 +43,13 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// - public Image(int width, int height, Bootstrapper bootstrapper = null) - : base(width, height, bootstrapper) + public Image(int width, int height, Configuration configuration = null) + : base(width, height, configuration) { - this.CurrentImageFormat = this.Bootstrapper.ImageFormats.First(); + this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } /// @@ -58,12 +58,12 @@ namespace ImageSharp /// /// The stream containing image information. /// - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(Stream stream, Bootstrapper bootstrapper = null) - : base(bootstrapper) + public Image(Stream stream, Configuration configuration = null) + : base(configuration) { Guard.NotNull(stream, nameof(stream)); this.Load(stream); @@ -75,12 +75,12 @@ namespace ImageSharp /// /// The byte array containing image information. /// - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(byte[] bytes, Bootstrapper bootstrapper = null) - : base(bootstrapper) + public Image(byte[] bytes, Configuration configuration = null) + : base(configuration) { Guard.NotNull(bytes, nameof(bytes)); @@ -296,7 +296,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - Image target = new Image(this.Width, this.Height, this.Bootstrapper) + Image target = new Image(this.Width, this.Height, this.Configuration) { Quality = this.Quality, FrameDelay = this.FrameDelay, @@ -312,7 +312,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - this.Bootstrapper.ParallelOptions, + this.Configuration.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) @@ -376,7 +376,7 @@ namespace ImageSharp /// private void Load(Stream stream) { - if (!this.Bootstrapper.ImageFormats.Any()) + if (!this.Configuration.ImageFormats.Any()) { throw new NotSupportedException("No image formats have been configured."); } @@ -411,7 +411,7 @@ namespace ImageSharp StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); - foreach (IImageFormat format in this.Bootstrapper.ImageFormats) + foreach (IImageFormat format in this.Configuration.ImageFormats) { stringBuilder.AppendLine("-" + format); } @@ -428,7 +428,7 @@ namespace ImageSharp /// private bool Decode(Stream stream) { - int maxHeaderSize = this.Bootstrapper.MaxHeaderSize; + int maxHeaderSize = this.Configuration.MaxHeaderSize; if (maxHeaderSize <= 0) { return false; @@ -441,7 +441,7 @@ namespace ImageSharp long startPosition = stream.Position; stream.Read(header, 0, maxHeaderSize); stream.Position = startPosition; - format = this.Bootstrapper.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); + format = this.Configuration.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); } finally { diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index dc8c33dbe..b4f02c7be 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -61,7 +61,7 @@ namespace ImageSharp this.pixelsBase = (byte*)this.dataPointer.ToPointer(); this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; - this.ParallelOptions = image.Bootstrapper.ParallelOptions; + this.ParallelOptions = image.Configuration.ParallelOptions; } /// @@ -88,7 +88,7 @@ namespace ImageSharp this.pixelsBase = (byte*)this.dataPointer.ToPointer(); this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; - this.ParallelOptions = Bootstrapper.Default.ParallelOptions; + this.ParallelOptions = Configuration.Default.ParallelOptions; } /// diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs index 66a2049e8..89f7b9ad5 100644 --- a/src/ImageSharp/ImageFrame.cs +++ b/src/ImageSharp/ImageFrame.cs @@ -18,11 +18,11 @@ namespace ImageSharp /// /// The width of the image in pixels. /// The height of the image in pixels. - /// - /// The bootstrapper providing initialization code which allows extending the library. + /// + /// The configuration providing initialization code which allows extending the library. /// - public ImageFrame(int width, int height, Bootstrapper bootstrapper = null) - : base(width, height, bootstrapper) + 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 57c921893..49b60b678 100644 --- a/src/ImageSharp/ImageProcessor.cs +++ b/src/ImageSharp/ImageProcessor.cs @@ -26,7 +26,7 @@ namespace ImageSharp.Processors { if (this.ParallelOptions == null) { - this.ParallelOptions = source.Bootstrapper.ParallelOptions; + this.ParallelOptions = source.Configuration.ParallelOptions; } try diff --git a/src/ImageSharp/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index b34398448..7a42090c7 100644 --- a/src/ImageSharp/Quantizers/Quantize.cs +++ b/src/ImageSharp/Quantizers/Quantize.cs @@ -65,7 +65,7 @@ namespace ImageSharp Parallel.For( 0, pixelCount, - source.Bootstrapper.ParallelOptions, + source.Configuration.ParallelOptions, i => { TColor color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])]; diff --git a/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs b/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs index b17dc7aaf..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.Default.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/ConfigurationTests.cs similarity index 84% rename from tests/ImageSharp.Tests/BootstrapperTests.cs rename to tests/ImageSharp.Tests/ConfigurationTests.cs index 096b9f0d5..507b835fb 100644 --- a/tests/ImageSharp.Tests/BootstrapperTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -11,7 +11,7 @@ namespace ImageSharp.Tests using Xunit; using System.Linq; - public class BootstrapperTests + public class ConfigurationTests { private class TestFormat : IImageFormat { @@ -52,7 +52,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(null); + Configuration.Default.AddImageFormat(null); }); var format = new TestFormat(); @@ -60,7 +60,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("decoder", exception.Message); @@ -69,7 +69,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("encoder", exception.Message); @@ -78,7 +78,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("mime type", exception.Message); @@ -87,7 +87,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("mime type", exception.Message); @@ -96,7 +96,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("extension", exception.Message); @@ -105,7 +105,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("extension", exception.Message); @@ -114,7 +114,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("supported extensions", exception.Message); @@ -123,7 +123,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("supported extensions", exception.Message); } @@ -136,14 +136,14 @@ namespace ImageSharp.Tests format.Extension = "test"; var exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("should contain", exception.Message); format.SupportedExtensions = new string[] { "test", "" }; exception = Assert.Throws(() => { - Bootstrapper.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat(format); }); Assert.Contains("empty values", exception.Message); } diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 65f712f72..566796bf8 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -42,10 +42,10 @@ namespace ImageSharp.Tests { // Register the individual image formats. // TODO: Is this the best place to do this? - Bootstrapper.Default.AddImageFormat(new PngFormat()); - Bootstrapper.Default.AddImageFormat(new JpegFormat()); - Bootstrapper.Default.AddImageFormat(new BmpFormat()); - Bootstrapper.Default.AddImageFormat(new GifFormat()); + Configuration.Default.AddImageFormat(new PngFormat()); + Configuration.Default.AddImageFormat(new JpegFormat()); + Configuration.Default.AddImageFormat(new BmpFormat()); + Configuration.Default.AddImageFormat(new GifFormat()); } /// diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 5fc9f175e..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.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); + return Configuration.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); } private string GetTestOutputDir() From 09d01a1d375b22d5ecd7a20ce04c1ce5ec030a14 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 1 Jan 2017 13:13:38 +1100 Subject: [PATCH 09/10] Throw useful error --- src/ImageSharp/Image/Image{TColor}.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 4d9511835..ed556f2f3 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -49,6 +49,11 @@ namespace ImageSharp public Image(int width, int height, Configuration configuration = null) : base(width, height, configuration) { + if (!this.Configuration.ImageFormats.Any()) + { + throw new NotSupportedException("No image formats have been configured."); + } + this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } From b867c05951a9444da3d3d61c3755d8d312b3e107 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 1 Jan 2017 13:13:53 +1100 Subject: [PATCH 10/10] Better configuration tests --- tests/ImageSharp.Tests/ConfigurationTests.cs | 285 ++++++++++++++----- 1 file changed, 211 insertions(+), 74 deletions(-) diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 507b835fb..74a077341 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -7,145 +7,282 @@ namespace ImageSharp.Tests { using System; using System.Collections.Generic; + using System.Linq; + using ImageSharp.Formats; + using Xunit; - using System.Linq; + /// + /// Tests the configuration class. + /// public class ConfigurationTests { - private class TestFormat : IImageFormat + /// + /// Test that the default configuration is not null. + /// + [Fact] + public void TestDefultConfigurationIsNotNull() { - 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; } } + Assert.True(Configuration.Default != null); + } - public IImageEncoder Encoder { get { return this.encoder; } set { this.encoder = value; } } + /// + /// Test that the default configuration parallel options is not null. + /// + [Fact] + public void TestDefultConfigurationParallelOptionsIsNotNull() + { + Assert.True(Configuration.Default.ParallelOptions != null); + } - public string MimeType { get { return this.mimeType; } set { this.mimeType = value; } } + /// + /// 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); + } - public string Extension { get { return this.extension; } set { this.extension = value; } } + /// + /// Test that the default configuration parallel options is not null. + /// + [Fact] + public void TestDefultConfigurationImageFormatsIsNotNull() + { + Assert.True(Configuration.Default.ImageFormats != null); + } - public IEnumerable SupportedExtensions { get { return this.supportedExtensions; } set { this.supportedExtensions = value; } } + /// + /// Tests the method throws an exception + /// when the format is null. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullFormat() + { + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(null); + }); + } - public int HeaderSize { get { throw new NotImplementedException(); } } + /// + /// Tests the method throws an exception + /// when the encoder is null. + /// + [Fact] + public void TestAddImageFormatThrowsWithNullEncoder() + { + TestFormat format = new TestFormat { Encoder = null }; - public bool IsSupportedFileFormat(byte[] header) { throw new NotImplementedException(); } + Assert.Throws(() => + { + Configuration.Default.AddImageFormat(format); + }); } + /// + /// Tests the method throws an exception + /// when the decoder is null. + /// [Fact] - public void AddImageFormatGuardNull() + public void TestAddImageFormatThrowsWithNullDecoder() { - ArgumentException exception; + TestFormat format = new TestFormat { Decoder = null }; - exception = Assert.Throws(() => + Assert.Throws(() => { - Configuration.Default.AddImageFormat(null); + Configuration.Default.AddImageFormat(format); }); + } - var format = new TestFormat(); - format.Decoder = null; + /// + /// 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 }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("decoder", exception.Message); - format = new TestFormat(); - format.Encoder = null; + format = new TestFormat { MimeType = string.Empty }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("encoder", exception.Message); + } - format = new TestFormat(); - format.MimeType = null; + /// + /// 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 }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("mime type", exception.Message); - format = new TestFormat(); - format.MimeType = ""; + format = new TestFormat { Extension = string.Empty }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("mime type", exception.Message); + } - format = new TestFormat(); - format.Extension = null; + /// + /// 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 }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("extension", exception.Message); - format = new TestFormat(); - format.Extension = ""; + format = new TestFormat { SupportedExtensions = Enumerable.Empty() }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("extension", exception.Message); + } - format = new TestFormat(); - format.SupportedExtensions = null; + /// + /// 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" }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("supported extensions", exception.Message); + } - format = new TestFormat(); - format.SupportedExtensions = Enumerable.Empty(); + /// + /// 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 } + }; - exception = Assert.Throws(() => + Assert.Throws(() => { Configuration.Default.AddImageFormat(format); }); - Assert.Contains("supported extensions", exception.Message); } + /// + /// 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 AddImageFormatChecks() + public void TestImageUsesDefaultConfiguration() { - TestFormat format = new TestFormat(); + 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); + } - format.Extension = "test"; - var exception = Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - Assert.Contains("should contain", exception.Message); + /// + /// Test that the default image constructor copies the configuration. + /// + [Fact] + public void TestImageCopiesConfiguration() + { + Configuration.Default.AddImageFormat(new PngFormat()); - format.SupportedExtensions = new string[] { "test", "" }; - exception = Assert.Throws(() => + 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() { - Configuration.Default.AddImageFormat(format); - }); - Assert.Contains("empty values", exception.Message); + 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