diff --git a/src/ImageSharp/Bootstrapper.cs b/src/ImageSharp/Bootstrapper.cs index de4bcc938..a73205a76 100644 --- a/src/ImageSharp/Bootstrapper.cs +++ b/src/ImageSharp/Bootstrapper.cs @@ -19,16 +19,25 @@ namespace ImageSharp public class Bootstrapper { /// - /// A new instance Initializes a new instance of the class. - /// with lazy initialization. + /// A singleton of the class. /// - private static readonly Lazy Lazy = new Lazy(() => new Bootstrapper()); + private static readonly Bootstrapper Instance = new Bootstrapper(); /// - /// The default list of supported + /// The list of supported . /// private readonly List imageFormats; + /// + /// The parallel options for processing tasks in parallel. + /// + private readonly ParallelOptions parallelOptions; + + /// + /// An object that can be used to synchronize access to the . + /// + private readonly object syncRoot = new object(); + /// /// Prevents a default instance of the class from being created. /// @@ -41,28 +50,24 @@ namespace ImageSharp new PngFormat(), new GifFormat() }; + this.parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; } - /// - /// Gets the current bootstrapper instance. - /// - public static Bootstrapper Instance => Lazy.Value; - /// /// Gets the collection of supported /// - public IReadOnlyCollection ImageFormats => new ReadOnlyCollection(this.imageFormats); + public static IReadOnlyCollection ImageFormats => new ReadOnlyCollection(Instance.imageFormats); /// - /// Gets or sets the global parallel options for processing tasks in parallel. + /// Gets the global parallel options for processing tasks in parallel. /// - public ParallelOptions ParallelOptions { get; set; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; + public static ParallelOptions ParallelOptions => Instance.parallelOptions; /// /// Adds a new to the collection of supported image formats. /// /// The new format to add. - public void AddImageFormat(IImageFormat format) + public static void AddImageFormat(IImageFormat format) { Guard.NotNull(format, nameof(format)); Guard.NotNull(format.Encoder, nameof(format), "The encoder should not be null."); @@ -71,9 +76,17 @@ 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."); - GuardDuplicate(format); + Instance.AddImageFormatLocked(format); + } - this.imageFormats.Add(format); + private void AddImageFormatLocked(IImageFormat format) + { + lock (this.syncRoot) + { + this.GuardDuplicate(format); + + this.imageFormats.Add(format); + } } private void GuardDuplicate(IImageFormat format) diff --git a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs index c209cde3f..66882e492 100644 --- a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs @@ -1286,7 +1286,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { int yoff = this.grayImage.GetRowOffset(y); @@ -1324,7 +1324,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { int yo = this.ycbcrImage.GetRowYOffset(y); @@ -1366,7 +1366,7 @@ namespace ImageSharp.Formats Parallel.For( 0, height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { int yo = this.ycbcrImage.GetRowYOffset(y); diff --git a/src/ImageSharp/Image/Image.cs b/src/ImageSharp/Image/Image.cs index 1b9b27338..d9ad0078a 100644 --- a/src/ImageSharp/Image/Image.cs +++ b/src/ImageSharp/Image/Image.cs @@ -43,7 +43,7 @@ namespace ImageSharp /// public Image() { - this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); + this.CurrentImageFormat = Bootstrapper.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); } /// @@ -55,7 +55,7 @@ namespace ImageSharp public Image(int width, int height) : base(width, height) { - this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); + this.CurrentImageFormat = Bootstrapper.ImageFormats.First(f => f.GetType() == typeof(PngFormat)); } /// @@ -91,11 +91,6 @@ namespace ImageSharp this.CopyProperties(other); } - /// - /// Gets a list of supported image formats. - /// - public IReadOnlyCollection Formats { get; } = Bootstrapper.Instance.ImageFormats; - /// /// Gets or sets the resolution of the image in x- direction. It is defined as /// number of dots per inch and should be an positive value. @@ -288,7 +283,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) @@ -352,7 +347,7 @@ namespace ImageSharp /// private void Load(Stream stream) { - if (!this.Formats.Any()) + if (!Bootstrapper.ImageFormats.Any()) { return; } @@ -387,7 +382,7 @@ namespace ImageSharp StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); - foreach (IImageFormat format in this.Formats) + foreach (IImageFormat format in Bootstrapper.ImageFormats) { stringBuilder.AppendLine("-" + format); } @@ -404,7 +399,7 @@ namespace ImageSharp /// private bool Decode(Stream stream) { - int maxHeaderSize = this.Formats.Max(x => x.Decoder.HeaderSize); + int maxHeaderSize = Bootstrapper.ImageFormats.Max(x => x.Decoder.HeaderSize); if (maxHeaderSize > 0) { byte[] header = new byte[maxHeaderSize]; @@ -413,7 +408,7 @@ namespace ImageSharp stream.Read(header, 0, maxHeaderSize); stream.Position = 0; - IImageFormat format = this.Formats.FirstOrDefault(x => x.Decoder.IsSupportedFileFormat(header)); + IImageFormat format = Bootstrapper.ImageFormats.FirstOrDefault(x => x.Decoder.IsSupportedFileFormat(header)); if (format != null) { format.Decoder.Decode(this, stream); diff --git a/src/ImageSharp/Image/ImageFrame.cs b/src/ImageSharp/Image/ImageFrame.cs index 5e9c9fb9b..dff5d1746 100644 --- a/src/ImageSharp/Image/ImageFrame.cs +++ b/src/ImageSharp/Image/ImageFrame.cs @@ -67,7 +67,7 @@ namespace ImageSharp Parallel.For( 0, target.Height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) diff --git a/src/ImageSharp/ImageProcessor.cs b/src/ImageSharp/ImageProcessor.cs index 3da7496fe..4b92eb5d1 100644 --- a/src/ImageSharp/ImageProcessor.cs +++ b/src/ImageSharp/ImageProcessor.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Processors where TPacked : struct, IEquatable { /// - public virtual ParallelOptions ParallelOptions { get; set; } = Bootstrapper.Instance.ParallelOptions; + public virtual ParallelOptions ParallelOptions { get; set; } = Bootstrapper.ParallelOptions; /// public virtual bool Compand { get; set; } = false; diff --git a/src/ImageSharp/Quantizers/QuantizedImage.cs b/src/ImageSharp/Quantizers/QuantizedImage.cs index 600d8aa8f..2f690012a 100644 --- a/src/ImageSharp/Quantizers/QuantizedImage.cs +++ b/src/ImageSharp/Quantizers/QuantizedImage.cs @@ -79,7 +79,7 @@ namespace ImageSharp.Quantizers Parallel.For( 0, pixelCount, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, i => { TColor color = this.Palette[Math.Min(palletCount, this.Pixels[i])]; diff --git a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs index 2542537c7..6eef9633c 100644 --- a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs +++ b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs @@ -749,7 +749,7 @@ namespace ImageSharp.Quantizers Parallel.For( 0, height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.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 c70259db6..59f006b46 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.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { for (int x = 0; x < source.Width; x++) @@ -49,7 +49,7 @@ namespace ImageSharp.Benchmarks.Image Parallel.For( 0, source.Height, - Bootstrapper.Instance.ParallelOptions, + Bootstrapper.ParallelOptions, y => { sourcePixels.CopyBlock(0, y, targetPixels, 0, y, source.Width); diff --git a/tests/ImageSharp.Tests/BootstrapperTests.cs b/tests/ImageSharp.Tests/BootstrapperTests.cs index 4c8ca7f8f..df93f99c9 100644 --- a/tests/ImageSharp.Tests/BootstrapperTests.cs +++ b/tests/ImageSharp.Tests/BootstrapperTests.cs @@ -48,7 +48,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(null); + Bootstrapper.AddImageFormat(null); }); var format = new TestFormat(); @@ -56,7 +56,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("decoder", exception.Message); @@ -65,7 +65,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("encoder", exception.Message); @@ -74,7 +74,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("mime type", exception.Message); @@ -83,7 +83,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("mime type", exception.Message); @@ -92,7 +92,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("extension", exception.Message); @@ -101,7 +101,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("extension", exception.Message); @@ -110,7 +110,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("supported extensions", exception.Message); @@ -119,7 +119,7 @@ namespace ImageSharp.Tests exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("supported extensions", exception.Message); } @@ -131,28 +131,28 @@ namespace ImageSharp.Tests var exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("format with the same", exception.Message); format.Extension = "test"; exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("should contain", exception.Message); format.SupportedExtensions = new string[] { "test", "jpg" }; exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("supports the same", exception.Message); format.SupportedExtensions = new string[] { "test", "" }; exception = Assert.Throws(() => { - Bootstrapper.Instance.AddImageFormat(format); + Bootstrapper.AddImageFormat(format); }); Assert.Contains("empty values", exception.Message); }