diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index dc55112c9..e217fd9a6 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 4b1d4222c..22e6d47e9 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -15,6 +15,15 @@ namespace SixLabors.ImageSharp.Advanced /// public static class AdvancedImageExtensions { + /// + /// Accepts a to implement a double-dispatch pattern in order to + /// apply pixel-specific operations on non-generic instances + /// + /// The source. + /// The visitor. + public static void AcceptVisitor(this Image source, IImageVisitor visitor) + => source.Accept(visitor); + /// /// Gets the configuration for the image. /// diff --git a/src/ImageSharp/IImageVisitor.cs b/src/ImageSharp/Advanced/IImageVisitor.cs similarity index 64% rename from src/ImageSharp/IImageVisitor.cs rename to src/ImageSharp/Advanced/IImageVisitor.cs index 971c4d37c..ba8b13e2e 100644 --- a/src/ImageSharp/IImageVisitor.cs +++ b/src/ImageSharp/Advanced/IImageVisitor.cs @@ -3,13 +3,13 @@ using SixLabors.ImageSharp.PixelFormats; -namespace SixLabors.ImageSharp +namespace SixLabors.ImageSharp.Advanced { /// - /// A visitor to implement double-dispatch pattern in order to apply pixel-specific operations - /// on non-generic instances. The operation is dispatched by . + /// A visitor to implement a double-dispatch pattern in order to apply pixel-specific operations + /// on non-generic instances. /// - internal interface IImageVisitor + public interface IImageVisitor { /// /// Provides a pixel-specific implementation for a given operation. @@ -19,4 +19,4 @@ namespace SixLabors.ImageSharp void Visit(Image image) where TPixel : struct, IPixel; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/IImage.cs b/src/ImageSharp/IImage.cs index b9e2cee61..0d4dc3c9d 100644 --- a/src/ImageSharp/IImage.cs +++ b/src/ImageSharp/IImage.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -11,4 +11,4 @@ namespace SixLabors.ImageSharp public interface IImage : IImageInfo, IDisposable { } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index 57f60f2e7..d7fed9016 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.IO; using SixLabors.ImageSharp.Advanced; @@ -80,21 +81,11 @@ namespace SixLabors.ImageSharp /// Configuration IConfigurable.Configuration => this.Configuration; - /// - /// Gets a value indicating whether the image instance is disposed. - /// - public bool IsDisposed { get; private set; } - /// public void Dispose() { - if (this.IsDisposed) - { - return; - } - - this.IsDisposed = true; - this.DisposeImpl(); + this.Dispose(true); + GC.SuppressFinalize(this); } /// @@ -109,8 +100,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(encoder, nameof(encoder)); this.EnsureNotDisposed(); - EncodeVisitor visitor = new EncodeVisitor(encoder, stream); - this.AcceptVisitor(visitor); + this.AcceptVisitor(new EncodeVisitor(encoder, stream)); } /// @@ -130,13 +120,6 @@ namespace SixLabors.ImageSharp public abstract Image CloneAs(Configuration configuration) where TPixel2 : struct, IPixel; - /// - /// Accept a . - /// Implemented by invoking - /// with the pixel type of the image. - /// - internal abstract void AcceptVisitor(IImageVisitor visitor); - /// /// Update the size of the image after mutation. /// @@ -144,9 +127,23 @@ namespace SixLabors.ImageSharp protected void UpdateSize(Size size) => this.size = size; /// - /// Implements the Dispose logic. + /// Disposes the object and frees resources for the Garbage Collector. + /// + /// Whether to dispose of managed and unmanaged objects. + protected abstract void Dispose(bool disposing); + + /// + /// Throws if the image is disposed. + /// + internal abstract void EnsureNotDisposed(); + + /// + /// Accepts a . + /// Implemented by invoking + /// with the pixel type of the image. /// - protected abstract void DisposeImpl(); + /// The visitor. + internal abstract void Accept(IImageVisitor visitor); private class EncodeVisitor : IImageVisitor { diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 6ea2b234c..6cdc948d4 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -119,16 +119,5 @@ namespace SixLabors.ImageSharp return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; } } - - /// - /// Throws if the image is disposed. - /// - internal static void EnsureNotDisposed(this Image image) - { - if (image.IsDisposed) - { - throw new ObjectDisposedException(nameof(image), "Trying to execute an operation on a disposed image."); - } - } } } diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs index f3fe1ed8d..91872b21d 100644 --- a/src/ImageSharp/ImageFrame.cs +++ b/src/ImageSharp/ImageFrame.cs @@ -74,7 +74,17 @@ namespace SixLabors.ImageSharp public Rectangle Bounds() => new Rectangle(0, 0, this.Width, this.Height); /// - public abstract void Dispose(); + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes the object and frees resources for the Garbage Collector. + /// + /// Whether to dispose of managed and unmanaged objects. + protected abstract void Dispose(bool disposing); internal abstract void CopyPixelsTo(Span destination) where TDestinationPixel : struct, IPixel; diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 5c9ff489e..0436eb9d2 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp /// In all other cases it is the only frame of the image. /// /// The pixel format. - public sealed class ImageFrame : ImageFrame, IPixelSource, IDisposable + public sealed class ImageFrame : ImageFrame, IPixelSource where TPixel : struct, IPixel { private bool isDisposed; @@ -196,20 +196,20 @@ namespace SixLabors.ImageSharp this.UpdateSize(this.PixelBuffer.Size()); } - /// - /// Disposes the object and frees resources for the Garbage Collector. - /// - public override void Dispose() + /// + protected override void Dispose(bool disposing) { if (this.isDisposed) { return; } - this.PixelBuffer?.Dispose(); - this.PixelBuffer = null; + if (disposing) + { + this.PixelBuffer?.Dispose(); + this.PixelBuffer = null; + } - // Note disposing is done. this.isDisposed = true; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index a7ea58652..3f733479d 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -21,6 +21,8 @@ namespace SixLabors.ImageSharp public sealed class Image : Image where TPixel : struct, IPixel { + private bool isDisposed; + /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -185,19 +187,41 @@ namespace SixLabors.ImageSharp } /// - protected override void DisposeImpl() => this.Frames.Dispose(); + protected override void Dispose(bool disposing) + { + if (this.isDisposed) + { + return; + } + + if (disposing) + { + this.Frames.Dispose(); + } + + this.isDisposed = true; + } + + /// + internal override void EnsureNotDisposed() + { + if (this.isDisposed) + { + throw new ObjectDisposedException("Trying to execute an operation on a disposed image."); + } + } + + /// + public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; /// - internal override void AcceptVisitor(IImageVisitor visitor) + internal override void Accept(IImageVisitor visitor) { this.EnsureNotDisposed(); visitor.Visit(this); } - /// - public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; - /// /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. /// diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs index 48876251e..40b1c439e 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs @@ -25,8 +25,7 @@ namespace SixLabors.ImageSharp.Processing Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); - var visitor = new ProcessingVisitor(operation, true); - source.AcceptVisitor(visitor); + source.AcceptVisitor(new ProcessingVisitor(operation, true)); } /// @@ -42,8 +41,10 @@ namespace SixLabors.ImageSharp.Processing Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); - IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider - .CreateImageProcessingContext(source, true); + IInternalImageProcessingContext operationsRunner + = source.GetConfiguration() + .ImageOperationsProvider.CreateImageProcessingContext(source, true); + operation(operationsRunner); } @@ -60,8 +61,10 @@ namespace SixLabors.ImageSharp.Processing Guard.NotNull(operations, nameof(operations)); source.EnsureNotDisposed(); - IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider - .CreateImageProcessingContext(source, true); + IInternalImageProcessingContext operationsRunner + = source.GetConfiguration() + .ImageOperationsProvider.CreateImageProcessingContext(source, true); + operationsRunner.ApplyProcessors(operations); } @@ -96,8 +99,10 @@ namespace SixLabors.ImageSharp.Processing Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); - IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider - .CreateImageProcessingContext(source, false); + IInternalImageProcessingContext operationsRunner + = source.GetConfiguration() + .ImageOperationsProvider.CreateImageProcessingContext(source, false); + operation(operationsRunner); return operationsRunner.GetResultImage(); } @@ -116,8 +121,10 @@ namespace SixLabors.ImageSharp.Processing Guard.NotNull(operations, nameof(operations)); source.EnsureNotDisposed(); - IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider - .CreateImageProcessingContext(source, false); + IInternalImageProcessingContext operationsRunner + = source.GetConfiguration() + .ImageOperationsProvider.CreateImageProcessingContext(source, false); + operationsRunner.ApplyProcessors(operations); return operationsRunner.GetResultImage(); } @@ -157,8 +164,10 @@ namespace SixLabors.ImageSharp.Processing public void Visit(Image image) where TPixel : struct, IPixel { - IInternalImageProcessingContext operationsRunner = image.GetConfiguration() - .ImageOperationsProvider.CreateImageProcessingContext(image, this.mutate); + IInternalImageProcessingContext operationsRunner = + image.GetConfiguration() + .ImageOperationsProvider.CreateImageProcessingContext(image, this.mutate); + this.operation(operationsRunner); this.ResultImage = operationsRunner.GetResultImage(); } diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs index 8b3e1eb96..c2c869052 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors internal abstract class CloningImageProcessor : ICloningImageProcessor where TPixel : struct, IPixel { - private bool isDisposed; - /// /// Initializes a new instance of the class. /// @@ -104,6 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public void Dispose() { this.Dispose(true); + GC.SuppressFinalize(this); } /// @@ -160,10 +159,6 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Whether to dispose managed and unmanaged objects. protected virtual void Dispose(bool disposing) { - if (!this.isDisposed) - { - this.isDisposed = true; - } } } } diff --git a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs index 53eedfd20..feb4c9f19 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs index 8ac8cd67b..55b4d3dc7 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors internal abstract class ImageProcessor : IImageProcessor where TPixel : struct, IPixel { - private bool isDisposed; - /// /// Initializes a new instance of the class. /// @@ -97,6 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// public virtual void Dispose() { + this.Dispose(true); + GC.SuppressFinalize(this); } /// @@ -142,10 +142,6 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Whether to dispose managed and unmanaged objects. protected virtual void Dispose(bool disposing) { - if (!this.isDisposed) - { - this.isDisposed = true; - } } } }