Browse Source

Do not dispose of source Fix #404

Former-commit-id: 5bcb4977e45de08f9c1c0c15583dc5140356609f
Former-commit-id: 5f21f6f1488a284413427231b76e0ad71eca9240
Former-commit-id: 8a227c50ce892ce7a1189015f3a2bbbb26c6e20d
af/merge-core
James Jackson-South 10 years ago
parent
commit
282bc9f8c8
  1. 2
      src/ImageProcessorCore/ImageBase.cs
  2. 26
      src/ImageProcessorCore/ImageExtensions.cs
  3. 36
      tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

2
src/ImageProcessorCore/ImageBase.cs

@ -41,7 +41,7 @@ namespace ImageProcessorCore
/// method will not dispose again. This help not to prolong the entity's /// method will not dispose again. This help not to prolong the entity's
/// life in the Garbage Collector. /// life in the Garbage Collector.
/// </remarks> /// </remarks>
protected bool IsDisposed; internal bool IsDisposed;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageBase"/> class. /// Initializes a new instance of the <see cref="ImageBase"/> class.

26
src/ImageProcessorCore/ImageExtensions.cs

@ -78,9 +78,7 @@ namespace ImageProcessorCore
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor) public static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor)
{ {
source = PerformAction(source, true, (sourceImage, targetImage) => processor.Apply(targetImage, sourceImage, sourceRectangle)); return PerformAction(source, true, (sourceImage, targetImage) => processor.Apply(targetImage, sourceImage, sourceRectangle));
return source;
} }
/// <summary> /// <summary>
@ -94,7 +92,7 @@ namespace ImageProcessorCore
/// <param name="height">The target image height.</param> /// <param name="height">The target image height.</param>
/// <param name="sampler">The processor to apply to the image.</param> /// <param name="sampler">The processor to apply to the image.</param>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
internal static Image Process(this Image source, int width, int height, IImageSampler sampler) public static Image Process(this Image source, int width, int height, IImageSampler sampler)
{ {
return Process(source, width, height, source.Bounds, default(Rectangle), sampler); return Process(source, width, height, source.Bounds, default(Rectangle), sampler);
} }
@ -102,8 +100,7 @@ namespace ImageProcessorCore
/// <summary> /// <summary>
/// Applies the collection of processors to the image. /// Applies the collection of processors to the image.
/// <remarks> /// <remarks>
/// This method does will resize the target image if the source and target /// This method does will resize the target image if the source and target rectangles are different.
/// rectangles are different.
/// </remarks> /// </remarks>
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
@ -120,9 +117,7 @@ namespace ImageProcessorCore
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Process(this Image source, int width, int height, Rectangle sourceRectangle, Rectangle targetRectangle, IImageSampler sampler) public static Image Process(this Image source, int width, int height, Rectangle sourceRectangle, Rectangle targetRectangle, IImageSampler sampler)
{ {
source = PerformAction(source, false, (sourceImage, targetImage) => sampler.Apply(targetImage, sourceImage, width, height, targetRectangle, sourceRectangle)); return PerformAction(source, false, (sourceImage, targetImage) => sampler.Apply(targetImage, sourceImage, width, height, targetRectangle, sourceRectangle));
return source;
} }
/// <summary> /// <summary>
@ -134,6 +129,11 @@ namespace ImageProcessorCore
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
private static Image PerformAction(Image source, bool clone, Action<ImageBase, ImageBase> action) private static Image PerformAction(Image source, bool clone, Action<ImageBase, ImageBase> action)
{ {
if (source.IsDisposed)
{
throw new ObjectDisposedException("Image");
}
Image transformedImage = clone Image transformedImage = clone
? new Image(source) ? new Image(source)
: new Image : new Image
@ -165,9 +165,11 @@ namespace ImageProcessorCore
} }
} }
// Clean up. // According to http://stackoverflow.com/questions/37921815/idisposable-unmanaged-fields-reference-types-and-assignments/37922955#37922955
source.Dispose(); // There's no need to dispose of the original image as the GC will get around to cleaning it up now there are no references to the original data.
return transformedImage; // TODO: Investigate how log this is held onto and try to keep that to a minimum.
source = transformedImage;
return source;
} }
} }
} }

36
tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

@ -388,6 +388,42 @@
} }
} }
[Fact]
public void ImageShouldNotDispose()
{
if (!Directory.Exists("TestOutput/Dispose"))
{
Directory.CreateDirectory("TestOutput/Dispose");
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Stopwatch watch = Stopwatch.StartNew();
string filename = Path.GetFileName(file);
Image image = new Image(stream);
image = image.BackgroundColor(Color.RebeccaPurple);
using (FileStream output = File.OpenWrite($"TestOutput/Dispose/{filename}"))
{
ResizeOptions options = new ResizeOptions()
{
Size = new Size(image.Width - 200, image.Height),
Mode = ResizeMode.Stretch
};
image.Resize(options, this.ProgressUpdate)
.Save(output);
}
image.Dispose();
Trace.WriteLine($"{filename}: {watch.ElapsedMilliseconds}ms");
}
}
}
[Theory] [Theory]
[MemberData("RotateFlips")] [MemberData("RotateFlips")]
public void ImageShouldRotateFlip(RotateType rotateType, FlipType flipType) public void ImageShouldRotateFlip(RotateType rotateType, FlipType flipType)

Loading…
Cancel
Save