Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Check if image is disposed
in significant Image and Image<T> methods
  • Loading branch information
antonfirsov committed Aug 11, 2019
commit 2744e5bcd4d8362124ebc07ab50cf421eef8b4c0
21 changes: 20 additions & 1 deletion src/ImageSharp/Image.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,22 @@ internal Image(
/// </summary>
Configuration IConfigurable.Configuration => this.Configuration;

/// <summary>
/// Gets a value indicating whether the image instance is disposed.
/// </summary>
public bool IsDisposed { get; private set; }

/// <inheritdoc />
public abstract void Dispose();
public void Dispose()
{
if (this.IsDisposed)
{
return;
}

this.IsDisposed = true;
this.DisposeImpl();
}

/// <summary>
/// Saves the image to the given stream using the given image encoder.
Expand Down Expand Up @@ -128,6 +142,11 @@ public abstract Image<TPixel2> CloneAs<TPixel2>(Configuration configuration)
/// <param name="size">The <see cref="Size"/>.</param>
protected void UpdateSize(Size size) => this.size = size;

/// <summary>
/// Implements the Dispose logic.
/// </summary>
protected abstract void DisposeImpl();

private class EncodeVisitor : IImageVisitor
{
private readonly IImageEncoder encoder;
Expand Down
13 changes: 12 additions & 1 deletion src/ImageSharp/ImageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,16 @@ public static string ToBase64String<TPixel>(this Image<TPixel> source, IImageFor
return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
}
}

/// <summary>
/// Throws <see cref="ObjectDisposedException"/> if the image is disposed.
/// </summary>
internal static void CheckDisposed(this Image image)
{
if (image.IsDisposed)
{
throw new ObjectDisposedException(nameof(image), "Trying to execute an operation on a disposed image.");
}
}
}
}
}
8 changes: 7 additions & 1 deletion src/ImageSharp/Image{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ internal Image(Configuration configuration, ImageMetadata metadata, IEnumerable<
/// <returns>Returns a new <see cref="Image{TPixel}"/> with all the same pixel data as the original.</returns>
public Image<TPixel> Clone(Configuration configuration)
{
this.CheckDisposed();

IEnumerable<ImageFrame<TPixel>> clonedFrames =
this.Frames.Select<ImageFrame<TPixel>, ImageFrame<TPixel>>(x => x.Clone(configuration));
return new Image<TPixel>(configuration, this.Metadata.DeepClone(), clonedFrames);
Expand All @@ -175,17 +177,21 @@ public Image<TPixel> Clone(Configuration configuration)
/// <returns>The <see cref="Image{TPixel2}"/>.</returns>
public override Image<TPixel2> CloneAs<TPixel2>(Configuration configuration)
{
this.CheckDisposed();

IEnumerable<ImageFrame<TPixel2>> clonedFrames =
this.Frames.Select<ImageFrame<TPixel>, ImageFrame<TPixel2>>(x => x.CloneAs<TPixel2>(configuration));
return new Image<TPixel2>(configuration, this.Metadata.DeepClone(), clonedFrames);
}

/// <inheritdoc/>
public override void Dispose() => this.Frames.Dispose();
protected override void DisposeImpl() => this.Frames.Dispose();

/// <inheritdoc />
internal override void AcceptVisitor(IImageVisitor visitor)
{
this.CheckDisposed();

visitor.Visit(this);
}

Expand Down
20 changes: 19 additions & 1 deletion tests/ImageSharp.Tests/Image/ImageCloneTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ namespace SixLabors.ImageSharp.Tests
{
public class ImageCloneTests
{
[Fact]
public void CloneAs_WhenDisposed_Throws()
{
Image<Rgba32> image = new Image<Rgba32>(5, 5);
image.Dispose();

Assert.Throws<ObjectDisposedException>(() => image.CloneAs<Bgra32>());
}

[Fact]
public void Clone_WhenDisposed_Throws()
{
Image<Rgba32> image = new Image<Rgba32>(5, 5);
image.Dispose();

Assert.Throws<ObjectDisposedException>(() => image.Clone());
}

[Theory]
[WithTestPatternImages(9, 9, PixelTypes.Rgba32)]
public void CloneAs_ToBgra32(TestImageProvider<Rgba32> provider)
Expand Down Expand Up @@ -109,4 +127,4 @@ public void CloneAs_ToRgb24(TestImageProvider<Rgba32> provider)
}
}
}
}
}
16 changes: 16 additions & 0 deletions tests/ImageSharp.Tests/Image/ImageTests.Save.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
// ReSharper disable InconsistentNaming

using System;
using System.IO;

using Moq;

using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
Expand Down Expand Up @@ -65,6 +69,18 @@ public void SetEncoding()
Assert.Equal("image/png", mime.DefaultMimeType);
}
}

[Fact]
public void ThrowsWhenDisposed()
{
var image = new Image<Rgba32>(5, 5);
image.Dispose();
IImageEncoder encoder = Mock.Of<IImageEncoder>();
using (MemoryStream stream = new MemoryStream())
{
Assert.Throws<ObjectDisposedException>(() => image.Save(stream, encoder));
}
}
}
}
}