From 2aabf49b568d49625068fc5fea3767617817756a Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 7 Apr 2016 00:48:36 +1000 Subject: [PATCH] Image now IDisposable This appears to have injected some voom into things. Not benchmarked though and needs double checking for memory leaks. touch #360 Former-commit-id: 0707a36781e3a5fa4d273d933d1bd1b04b022092 Former-commit-id: f7ec165c3d10d9e1e35b8eec3545ca75cf302cf9 Former-commit-id: d5bc57ce1cde9f1486a954d3453040514dc4d629 --- src/ImageProcessorCore/Filters/Blend.cs | 6 + .../Formats/Png/PngEncoder.cs | 2 +- .../Formats/Png/PngEncoderCore.cs | 2 +- src/ImageProcessorCore/IImageBase.cs | 2 +- src/ImageProcessorCore/Image.cs | 26 ++- src/ImageProcessorCore/ImageBase.cs | 156 ++++++++++++------ src/ImageProcessorCore/ImageExtensions.cs | 1 + .../ParallelImageProcessor.cs | 40 ++--- .../Samplers/EntropyCrop.cs | 25 +-- src/ImageProcessorCore/Samplers/Resize.cs | 2 + .../ImageProcessorCore.Tests/FileTestBase.cs | 2 +- .../Formats/BitmapTests.cs | 23 +-- .../Formats/EncoderDecoderTests.cs | 120 ++++++++------ .../Formats/PngTests.cs | 11 +- .../Processors/Filters/FilterTests.cs | 15 +- .../Processors/Samplers/SamplerTests.cs | 87 ++++++---- 16 files changed, 316 insertions(+), 204 deletions(-) diff --git a/src/ImageProcessorCore/Filters/Blend.cs b/src/ImageProcessorCore/Filters/Blend.cs index 9fffe51917..e48a26c520 100644 --- a/src/ImageProcessorCore/Filters/Blend.cs +++ b/src/ImageProcessorCore/Filters/Blend.cs @@ -73,5 +73,11 @@ namespace ImageProcessorCore.Filters } }); } + + /// + protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) + { + this.toBlend?.Dispose(); + } } } diff --git a/src/ImageProcessorCore/Formats/Png/PngEncoder.cs b/src/ImageProcessorCore/Formats/Png/PngEncoder.cs index 170144ca7b..18deb10466 100644 --- a/src/ImageProcessorCore/Formats/Png/PngEncoder.cs +++ b/src/ImageProcessorCore/Formats/Png/PngEncoder.cs @@ -18,7 +18,7 @@ namespace ImageProcessorCore.Formats /// /// Gets or sets the quality of output for images. /// - public int Quality { get; set; } = int.MaxValue; + public int Quality { get; set; } /// public string MimeType => "image/png"; diff --git a/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs b/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs index 89e3883b35..b2fdab0519 100644 --- a/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs +++ b/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs @@ -35,7 +35,7 @@ namespace ImageProcessorCore.Formats /// /// Gets or sets the quality of output for images. /// - public int Quality { get; set; } = int.MaxValue; + public int Quality { get; set; } /// /// The compression level 1-9. diff --git a/src/ImageProcessorCore/IImageBase.cs b/src/ImageProcessorCore/IImageBase.cs index 569dcecda9..c12406d9aa 100644 --- a/src/ImageProcessorCore/IImageBase.cs +++ b/src/ImageProcessorCore/IImageBase.cs @@ -17,7 +17,7 @@ namespace ImageProcessorCore /// /// /// The returned array has a length of Width * Height * 4 bytes - /// and stores the blue, the green, the red and the alpha value for + /// and stores the red, the green, the blue, and the alpha value for /// each pixel in this order. /// float[] Pixels { get; } diff --git a/src/ImageProcessorCore/Image.cs b/src/ImageProcessorCore/Image.cs index 0edbfb7566..745b617b38 100644 --- a/src/ImageProcessorCore/Image.cs +++ b/src/ImageProcessorCore/Image.cs @@ -45,7 +45,7 @@ namespace ImageProcessorCore new BmpFormat(), new JpegFormat(), new PngFormat(), - new GifFormat(), + new GifFormat() }); /// @@ -223,6 +223,30 @@ namespace ImageProcessorCore encoder.Encode(this, stream); } + /// + protected override void Dispose(bool disposing) + { + if (this.IsDisposed) + { + return; + } + + if (disposing) + { + // Dispose of any managed resources here. + if (this.Frames.Any()) + { + foreach (ImageFrame frame in this.Frames) + { + frame.Dispose(); + } + this.Frames.Clear(); + } + } + + base.Dispose(disposing); + } + /// /// Loads the image from the given stream. /// diff --git a/src/ImageProcessorCore/ImageBase.cs b/src/ImageProcessorCore/ImageBase.cs index 09a0ad741a..0065d61bca 100644 --- a/src/ImageProcessorCore/ImageBase.cs +++ b/src/ImageProcessorCore/ImageBase.cs @@ -6,13 +6,39 @@ namespace ImageProcessorCore { using System; + using System.Runtime.InteropServices; /// /// The base class of all images. Encapsulates the basic properties and methods /// required to manipulate images. /// - public abstract class ImageBase : IImageBase + public abstract unsafe class ImageBase : IImageBase, IDisposable { + /// + /// The position of the first pixel in the bitmap. + /// + private float* pixelsBase; + + /// + /// The array of pixels. + /// + private float[] pixelsArray; + + private GCHandle pixelsHandle; + + /// + /// A value indicating whether this instance of the given entity has been disposed. + /// + /// if this instance has been disposed; otherwise, . + /// + /// If the entity is disposed, it must not be disposed a second + /// time. The isDisposed field is set the first time the entity + /// is disposed. If the isDisposed field is true, then the Dispose() + /// method will not dispose again. This help not to prolong the entity's + /// life in the Garbage Collector. + /// + protected bool IsDisposed; + /// /// Initializes a new instance of the class. /// @@ -23,12 +49,8 @@ namespace ImageProcessorCore /// /// Initializes a new instance of the class. /// - /// - /// The width of the image in pixels. - /// - /// - /// The height of the image in pixels. - /// + /// The width of the image in pixels. + /// The height of the image in pixels. /// /// Thrown if either or are less than or equal to 0. /// @@ -40,7 +62,10 @@ namespace ImageProcessorCore this.Width = width; this.Height = height; - this.Pixels = new float[width * height * 4]; + // Assign the pointer and pixels. + this.pixelsArray = new float[width * height * 4]; + this.pixelsHandle = GCHandle.Alloc(this.pixelsArray, GCHandleType.Pinned); + this.pixelsBase = (float*)this.pixelsHandle.AddrOfPinnedObject().ToPointer(); } /// @@ -56,14 +81,22 @@ namespace ImageProcessorCore { Guard.NotNull(other, nameof(other), "Other image cannot be null."); - float[] pixels = other.Pixels; - this.Width = other.Width; this.Height = other.Height; this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; - this.Pixels = new float[pixels.Length]; - Array.Copy(pixels, this.Pixels, pixels.Length); + + // Assign the pointer and copy the pixels. + this.pixelsArray = new float[this.Width * this.Height * 4]; + this.pixelsHandle = GCHandle.Alloc(this.pixelsArray, GCHandleType.Pinned); + this.pixelsBase = (float*)this.pixelsHandle.AddrOfPinnedObject().ToPointer(); + Array.Copy(other.pixelsArray, this.pixelsArray, other.pixelsArray.Length); + } + + /// + ~ImageBase() + { + this.Dispose(false); } /// @@ -76,45 +109,25 @@ namespace ImageProcessorCore /// public static int MaxHeight { get; set; } = int.MaxValue; - /// - /// Gets the image pixels as byte array. - /// - /// - /// The returned array has a length of Width * Height * 4 bytes - /// and stores the blue, the green, the red and the alpha value for - /// each pixel in this order. - /// - public float[] Pixels { get; private set; } + /// + public float[] Pixels => this.pixelsArray; - /// - /// Gets the width in pixels. - /// + /// public int Width { get; private set; } - /// - /// Gets the height in pixels. - /// + /// public int Height { get; private set; } - /// - /// Gets the pixel ratio made up of the width and height. - /// + /// public double PixelRatio => (double)this.Width / this.Height; - /// - /// Gets the representing the bounds of the image. - /// + /// public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height); /// public int Quality { get; set; } - /// - /// Gets or sets the frame delay for animated images. - /// If not 0, this field specifies the number of hundredths (1/100) of a second to - /// wait before continuing with the processing of the Data Stream. - /// The clock starts ticking immediately after the graphic is rendered. - /// + /// public int FrameDelay { get; set; } /// @@ -133,9 +146,7 @@ namespace ImageProcessorCore throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); } #endif - - int start = ((y * this.Width) + x) * 4; - return new Color(this.Pixels[start], this.Pixels[start + 1], this.Pixels[start + 2], this.Pixels[start + 3]); + return *((Color*)(this.pixelsBase + ((y * this.Width) + x) * 4)); } set @@ -151,12 +162,7 @@ namespace ImageProcessorCore throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); } #endif - int start = ((y * this.Width) + x) * 4; - - this.Pixels[start + 0] = value.R; - this.Pixels[start + 1] = value.G; - this.Pixels[start + 2] = value.B; - this.Pixels[start + 3] = value.A; + *(Color*)(this.pixelsBase + (((y * this.Width) + x) * 4)) = value; } } @@ -181,7 +187,10 @@ namespace ImageProcessorCore #endif this.Width = width; this.Height = height; - this.Pixels = pixels; + + this.pixelsArray = pixels; + this.pixelsHandle = GCHandle.Alloc(this.pixelsArray, GCHandleType.Pinned); + this.pixelsBase = (float*)this.pixelsHandle.AddrOfPinnedObject().ToPointer(); } /// @@ -205,9 +214,52 @@ namespace ImageProcessorCore #endif this.Width = width; this.Height = height; - float[] clonedPixels = new float[pixels.Length]; - Array.Copy(pixels, clonedPixels, pixels.Length); - this.Pixels = clonedPixels; + + // Assign the pointer and copy the pixels. + this.pixelsArray = new float[pixels.Length]; + this.pixelsHandle = GCHandle.Alloc(this.pixelsArray, GCHandleType.Pinned); + this.pixelsBase = (float*)this.pixelsHandle.AddrOfPinnedObject().ToPointer(); + Array.Copy(pixels, this.pixelsArray, pixels.Length); + } + + /// + public void Dispose() + { + this.Dispose(true); + + // This object will be cleaned up by the Dispose method. + // Therefore, you should call GC.SuppressFinalize to + // take this object off the finalization queue + // and prevent finalization code for this object + // from executing a second time. + GC.SuppressFinalize(this); + } + + /// + /// Disposes the object and frees resources for the Garbage Collector. + /// + /// If true, the object gets disposed. + protected virtual void Dispose(bool disposing) + { + if (this.IsDisposed) + { + return; + } + + if (disposing) + { + // Dispose of any managed resources here. + this.pixelsArray = null; + } + + if (this.pixelsHandle.IsAllocated) + { + this.pixelsHandle.Free(); + this.pixelsBase = null; + } + + // Note disposing is done. + this.IsDisposed = true; } } } diff --git a/src/ImageProcessorCore/ImageExtensions.cs b/src/ImageProcessorCore/ImageExtensions.cs index 6a6d0e3f07..533d33701a 100644 --- a/src/ImageProcessorCore/ImageExtensions.cs +++ b/src/ImageProcessorCore/ImageExtensions.cs @@ -164,6 +164,7 @@ namespace ImageProcessorCore } } + source.Dispose(); return transformedImage; } } diff --git a/src/ImageProcessorCore/ParallelImageProcessor.cs b/src/ImageProcessorCore/ParallelImageProcessor.cs index c0de648007..297f796f80 100644 --- a/src/ImageProcessorCore/ParallelImageProcessor.cs +++ b/src/ImageProcessorCore/ParallelImageProcessor.cs @@ -37,10 +37,7 @@ namespace ImageProcessorCore { try { - // We don't want to affect the original source pixels so we make clone here. - ImageFrame frame = source as ImageFrame; - Image temp = frame != null ? new Image(frame) : new Image((Image)source); - this.OnApply(temp, target, target.Bounds, sourceRectangle); + this.OnApply(source, target, target.Bounds, sourceRectangle); this.numRowsProcessed = 0; this.totalRows = sourceRectangle.Height; @@ -54,24 +51,27 @@ namespace ImageProcessorCore for (int p = 0; p < partitionCount; p++) { int current = p; - tasks[p] = Task.Run(() => - { - int batchSize = sourceRectangle.Height / partitionCount; - int yStart = sourceRectangle.Y + (current * batchSize); - int yEnd = current == partitionCount - 1 ? sourceRectangle.Bottom : yStart + batchSize; - - this.Apply(target, temp, target.Bounds, sourceRectangle, yStart, yEnd); - }); + tasks[p] = Task.Run( + () => + { + int batchSize = sourceRectangle.Height / partitionCount; + int yStart = sourceRectangle.Y + (current * batchSize); + int yEnd = current == partitionCount - 1 + ? sourceRectangle.Bottom + : yStart + batchSize; + + this.Apply(target, source, target.Bounds, sourceRectangle, yStart, yEnd); + }); } Task.WaitAll(tasks); } else { - this.Apply(target, temp, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); + this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); } - this.AfterApply(temp, target, target.Bounds, sourceRectangle); + this.AfterApply(source, target, target.Bounds, sourceRectangle); } catch (Exception ex) { @@ -93,10 +93,7 @@ namespace ImageProcessorCore sourceRectangle = source.Bounds; } - // We don't want to affect the original source pixels so we make clone here. - ImageFrame frame = source as ImageFrame; - Image temp = frame != null ? new Image(frame) : new Image((Image)source); - this.OnApply(temp, target, target.Bounds, sourceRectangle); + this.OnApply(source, target, target.Bounds, sourceRectangle); targetRectangle = target.Bounds; this.numRowsProcessed = 0; @@ -117,7 +114,7 @@ namespace ImageProcessorCore int yStart = current * batchSize; int yEnd = current == partitionCount - 1 ? targetRectangle.Bottom : yStart + batchSize; - this.Apply(target, temp, targetRectangle, sourceRectangle, yStart, yEnd); + this.Apply(target, source, targetRectangle, sourceRectangle, yStart, yEnd); }); } @@ -125,14 +122,13 @@ namespace ImageProcessorCore } else { - this.Apply(target, temp, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom); + this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom); } - this.AfterApply(temp, target, target.Bounds, sourceRectangle); + this.AfterApply(source, target, target.Bounds, 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); } } diff --git a/src/ImageProcessorCore/Samplers/EntropyCrop.cs b/src/ImageProcessorCore/Samplers/EntropyCrop.cs index 928518d53c..32f3b384b2 100644 --- a/src/ImageProcessorCore/Samplers/EntropyCrop.cs +++ b/src/ImageProcessorCore/Samplers/EntropyCrop.cs @@ -42,20 +42,21 @@ namespace ImageProcessorCore.Samplers /// protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) { - ImageBase temp = new Image(source.Width, source.Height); - - // Detect the edges. - new Sobel().Apply(temp, source, sourceRectangle); + using (ImageBase temp = new Image(source.Width, source.Height)) + { + // Detect the edges. + new Sobel().Apply(temp, source, sourceRectangle); - // Apply threshold binarization filter. - new Threshold(.5f).Apply(temp, temp, sourceRectangle); + // Apply threshold binarization filter. + new Threshold(.5f).Apply(temp, temp, sourceRectangle); - // Search for the first white pixels - Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); + // Search for the first white pixels + Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); - // Reset the target pixel to the correct size. - target.SetPixels(rectangle.Width, rectangle.Height, new float[rectangle.Width * rectangle.Height * 4]); - this.cropRectangle = rectangle; + // Reset the target pixel to the correct size. + target.SetPixels(rectangle.Width, rectangle.Height, new float[rectangle.Width * rectangle.Height * 4]); + this.cropRectangle = rectangle; + } } /// @@ -73,7 +74,7 @@ namespace ImageProcessorCore.Samplers int endX = this.cropRectangle.Width; int maxX = this.cropRectangle.Right - 1; int maxY = this.cropRectangle.Bottom - 1; - + Parallel.For( startY, endY, diff --git a/src/ImageProcessorCore/Samplers/Resize.cs b/src/ImageProcessorCore/Samplers/Resize.cs index ce4d513ac6..275f72454f 100644 --- a/src/ImageProcessorCore/Samplers/Resize.cs +++ b/src/ImageProcessorCore/Samplers/Resize.cs @@ -164,6 +164,8 @@ namespace ImageProcessorCore.Samplers { target.ClonePixels(target.Width, target.Height, source.Pixels); } + + this.firstPass?.Dispose(); } } } \ No newline at end of file diff --git a/tests/ImageProcessorCore.Tests/FileTestBase.cs b/tests/ImageProcessorCore.Tests/FileTestBase.cs index d5471f4299..6c5079cd1b 100644 --- a/tests/ImageProcessorCore.Tests/FileTestBase.cs +++ b/tests/ImageProcessorCore.Tests/FileTestBase.cs @@ -29,7 +29,7 @@ namespace ImageProcessorCore.Tests //"TestImages/Formats/Png/indexed.png", // Perf: Enable for local testing only "TestImages/Formats/Png/splash.png", "TestImages/Formats/Gif/rings.gif", - //"TestImages/Formats/Gif/giphy.gif" // Perf: Enable for local testing only + "TestImages/Formats/Gif/giphy.gif" // Perf: Enable for local testing only }; protected void ProgressUpdate(object sender, ProgressEventArgs e) diff --git a/tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs b/tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs index 92589ee889..68b4ea2b0c 100644 --- a/tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs +++ b/tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs @@ -27,20 +27,21 @@ namespace ImageProcessorCore.Tests using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - - string encodeFilename = "TestOutput/Encode/Bitmap/" + "24-" + Path.GetFileNameWithoutExtension(file) + ".bmp"; - - using (FileStream output = File.OpenWrite(encodeFilename)) + using (Image image = new Image(stream)) { - image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel24 }); - } + string encodeFilename = "TestOutput/Encode/Bitmap/" + "24-" + Path.GetFileNameWithoutExtension(file) + ".bmp"; - encodeFilename = "TestOutput/Encode/Bitmap/" + "32-" + Path.GetFileNameWithoutExtension(file) + ".bmp"; + using (FileStream output = File.OpenWrite(encodeFilename)) + { + image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel24 }); + } - using (FileStream output = File.OpenWrite(encodeFilename)) - { - image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel32 }); + encodeFilename = "TestOutput/Encode/Bitmap/" + "32-" + Path.GetFileNameWithoutExtension(file) + ".bmp"; + + using (FileStream output = File.OpenWrite(encodeFilename)) + { + image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel32 }); + } } Trace.WriteLine($"{file} : {watch.ElapsedMilliseconds}ms"); diff --git a/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs b/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs index 0b19d1b1ab..116399ccf0 100644 --- a/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs +++ b/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs @@ -30,13 +30,14 @@ namespace ImageProcessorCore.Tests using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - - string encodeFilename = "TestOutput/Encode/" + Path.GetFileName(file); - - using (FileStream output = File.OpenWrite(encodeFilename)) + using (Image image = new Image(stream)) { - image.Save(output); + string encodeFilename = "TestOutput/Encode/" + Path.GetFileName(file); + + using (FileStream output = File.OpenWrite(encodeFilename)) + { + image.Save(output); + } } Trace.WriteLine($"{file} : {watch.ElapsedMilliseconds}ms"); @@ -56,30 +57,37 @@ namespace ImageProcessorCore.Tests { using (FileStream stream = File.OpenRead(file)) { - Image image = new Image(stream); - - IQuantizer quantizer = new OctreeQuantizer(); - QuantizedImage quantizedImage = quantizer.Quantize(image, 256); - - using (FileStream output = File.OpenWrite($"TestOutput/Quantize/Octree-{Path.GetFileName(file)}")) + using (Image image = new Image(stream)) { - quantizedImage.ToImage().Save(output, image.CurrentImageFormat); - } + IQuantizer quantizer = new OctreeQuantizer(); + QuantizedImage quantizedImage = quantizer.Quantize(image, 256); - quantizer = new WuQuantizer(); - quantizedImage = quantizer.Quantize(image, 256); + using (FileStream output = File.OpenWrite($"TestOutput/Quantize/Octree-{Path.GetFileName(file)}")) + { + using (Image qi = quantizedImage.ToImage()) + { + qi.Save(output, image.CurrentImageFormat); + } + } - using (FileStream output = File.OpenWrite($"TestOutput/Quantize/Wu-{Path.GetFileName(file)}")) - { - quantizedImage.ToImage().Save(output, image.CurrentImageFormat); - } + quantizer = new WuQuantizer(); + quantizedImage = quantizer.Quantize(image, 256); - quantizer = new PaletteQuantizer(); - quantizedImage = quantizer.Quantize(image, 256); + using (FileStream output = File.OpenWrite($"TestOutput/Quantize/Wu-{Path.GetFileName(file)}")) + { + quantizedImage.ToImage().Save(output, image.CurrentImageFormat); + } - using (FileStream output = File.OpenWrite($"TestOutput/Quantize/Palette-{Path.GetFileName(file)}")) - { - quantizedImage.ToImage().Save(output, image.CurrentImageFormat); + quantizer = new PaletteQuantizer(); + quantizedImage = quantizer.Quantize(image, 256); + + using (FileStream output = File.OpenWrite($"TestOutput/Quantize/Palette-{Path.GetFileName(file)}")) + { + using (Image qi = quantizedImage.ToImage()) + { + qi.Save(output, image.CurrentImageFormat); + } + } } } } @@ -97,26 +105,27 @@ namespace ImageProcessorCore.Tests { using (FileStream stream = File.OpenRead(file)) { - Image image = new Image(stream); - - using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.gif")) + using (Image image = new Image(stream)) { - image.SaveAsGif(output); - } + using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.gif")) + { + image.SaveAsGif(output); + } - using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.bmp")) - { - image.SaveAsBmp(output); - } + using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.bmp")) + { + image.SaveAsBmp(output); + } - using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.jpg")) - { - image.SaveAsJpeg(output); - } + using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.jpg")) + { + image.SaveAsJpeg(output); + } - using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.png")) - { - image.SaveAsPng(output); + using (FileStream output = File.OpenWrite($"TestOutput/Format/{Path.GetFileNameWithoutExtension(file)}.png")) + { + image.SaveAsPng(output); + } } } } @@ -134,22 +143,25 @@ namespace ImageProcessorCore.Tests { using (FileStream stream = File.OpenRead(file)) { - Image image = new Image(stream); - byte[] serialized; - using (MemoryStream memoryStream = new MemoryStream()) + using (Image image = new Image(stream)) { - image.Save(memoryStream); - memoryStream.Flush(); - serialized = memoryStream.ToArray(); - } - - using (MemoryStream memoryStream = new MemoryStream(serialized)) - { - Image image2 = new Image(memoryStream); + byte[] serialized; + using (MemoryStream memoryStream = new MemoryStream()) + { + image.Save(memoryStream); + memoryStream.Flush(); + serialized = memoryStream.ToArray(); + } - using (FileStream output = File.OpenWrite($"TestOutput/Serialized/{Path.GetFileName(file)}")) + using (MemoryStream memoryStream = new MemoryStream(serialized)) { - image2.Save(output); + using (Image image2 = new Image(memoryStream)) + { + using (FileStream output = File.OpenWrite($"TestOutput/Serialized/{Path.GetFileName(file)}")) + { + image2.Save(output); + } + } } } } diff --git a/tests/ImageProcessorCore.Tests/Formats/PngTests.cs b/tests/ImageProcessorCore.Tests/Formats/PngTests.cs index 6c7029c85d..00e90b7942 100644 --- a/tests/ImageProcessorCore.Tests/Formats/PngTests.cs +++ b/tests/ImageProcessorCore.Tests/Formats/PngTests.cs @@ -25,12 +25,13 @@ namespace ImageProcessorCore.Tests { using (FileStream stream = File.OpenRead(file)) { - Image image = new Image(stream); - - using (FileStream output = File.OpenWrite($"TestOutput/Encode/Png/{Path.GetFileNameWithoutExtension(file)}.png")) + using (Image image = new Image(stream)) { - image.Quality = 256; - image.Save(output, new PngFormat()); + using (FileStream output = File.OpenWrite($"TestOutput/Encode/Png/{Path.GetFileNameWithoutExtension(file)}.png")) + { + image.Quality = 256; + image.Save(output, new PngFormat()); + } } } } diff --git a/tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs index 4e3fd103de..db48b7dd52 100644 --- a/tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs @@ -70,15 +70,16 @@ namespace ImageProcessorCore.Tests using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Filter/{ Path.GetFileName(filename) }")) + using (Image image = new Image(stream)) { - processor.OnProgress += this.ProgressUpdate; - image.Process(processor).Save(output); - processor.OnProgress -= this.ProgressUpdate; + string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/Filter/{Path.GetFileName(filename)}")) + { + processor.OnProgress += this.ProgressUpdate; + image.Process(processor).Save(output); + processor.OnProgress -= this.ProgressUpdate; + } } - Trace.WriteLine($"{ name }: { watch.ElapsedMilliseconds}ms"); } } diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs index 925d1340ba..4aaffb3283 100644 --- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs @@ -60,14 +60,16 @@ { Stopwatch watch = Stopwatch.StartNew(); Image image = new Image(stream); + string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Sample/{ Path.GetFileName(filename) }")) + using (FileStream output = File.OpenWrite($"TestOutput/Sample/{Path.GetFileName(filename)}")) { processor.OnProgress += this.ProgressUpdate; image = image.Process(image.Width / 2, image.Height / 2, processor); image.Save(output); processor.OnProgress -= this.ProgressUpdate; } + image.Dispose(); Trace.WriteLine($"{ name }: { watch.ElapsedMilliseconds}ms"); } @@ -88,14 +90,15 @@ using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) + using (Image image = new Image(stream)) { - image.Resize(image.Width / 2, image.Height / 2, sampler, false, this.ProgressUpdate) - .Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) + { + image.Resize(image.Width / 2, image.Height / 2, sampler, false, this.ProgressUpdate) + .Save(output); + } } - Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms"); } } @@ -116,12 +119,14 @@ using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) + using (Image image = new Image(stream)) { - image.Resize(image.Width / 3, 0, new TriangleResampler(), false, this.ProgressUpdate) - .Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) + { + image.Resize(image.Width / 3, 0, new TriangleResampler(), false, this.ProgressUpdate) + .Save(output); + } } Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms"); @@ -144,12 +149,14 @@ using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) + using (Image image = new Image(stream)) { - image.Resize(0, image.Height / 3, new TriangleResampler(), false, this.ProgressUpdate) - .Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) + { + image.Resize(0, image.Height / 3, new TriangleResampler(), false, this.ProgressUpdate) + .Save(output); + } } Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms"); @@ -171,12 +178,14 @@ using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-" + rotateType + flipType + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/RotateFlip/{filename}")) + using (Image image = new Image(stream)) { - image.RotateFlip(rotateType, flipType, this.ProgressUpdate) - .Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-" + rotateType + flipType + + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/RotateFlip/{filename}")) + { + image.RotateFlip(rotateType, flipType, this.ProgressUpdate).Save(output); + } } Trace.WriteLine($"{rotateType + "-" + flipType}: {watch.ElapsedMilliseconds}ms"); @@ -198,13 +207,15 @@ using (FileStream stream = File.OpenRead(file)) { Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}")) + using (Image image = new Image(stream)) { - image.Rotate(45, sampler, false, this.ProgressUpdate) - //.BackgroundColor(Color.Aqua) - .Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}")) + { + image.Rotate(45, sampler, false, this.ProgressUpdate) + //.BackgroundColor(Color.Aqua) + .Save(output); + } } Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms"); @@ -224,11 +235,13 @@ { using (FileStream stream = File.OpenRead(file)) { - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-EntropyCrop" + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/EntropyCrop/{filename}")) + using (Image image = new Image(stream)) { - image.EntropyCrop(.5f, this.ProgressUpdate).Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-EntropyCrop" + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/EntropyCrop/{filename}")) + { + image.EntropyCrop(.5f, this.ProgressUpdate).Save(output); + } } } } @@ -246,11 +259,13 @@ { using (FileStream stream = File.OpenRead(file)) { - Image image = new Image(stream); - string filename = Path.GetFileNameWithoutExtension(file) + "-Crop" + Path.GetExtension(file); - using (FileStream output = File.OpenWrite($"TestOutput/Crop/{filename}")) + using (Image image = new Image(stream)) { - image.Crop(image.Width / 2, image.Height / 2, this.ProgressUpdate).Save(output); + string filename = Path.GetFileNameWithoutExtension(file) + "-Crop" + Path.GetExtension(file); + using (FileStream output = File.OpenWrite($"TestOutput/Crop/{filename}")) + { + image.Crop(image.Width / 2, image.Height / 2, this.ProgressUpdate).Save(output); + } } } }