Browse Source

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
pull/1/head
James South 10 years ago
parent
commit
d12eedb9fe
  1. 6
      src/ImageProcessorCore/Filters/Blend.cs
  2. 2
      src/ImageProcessorCore/Formats/Png/PngEncoder.cs
  3. 2
      src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs
  4. 2
      src/ImageProcessorCore/IImageBase.cs
  5. 26
      src/ImageProcessorCore/Image.cs
  6. 156
      src/ImageProcessorCore/ImageBase.cs
  7. 1
      src/ImageProcessorCore/ImageExtensions.cs
  8. 40
      src/ImageProcessorCore/ParallelImageProcessor.cs
  9. 25
      src/ImageProcessorCore/Samplers/EntropyCrop.cs
  10. 2
      src/ImageProcessorCore/Samplers/Resize.cs
  11. 2
      tests/ImageProcessorCore.Tests/FileTestBase.cs
  12. 23
      tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs
  13. 120
      tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs
  14. 11
      tests/ImageProcessorCore.Tests/Formats/PngTests.cs
  15. 15
      tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs
  16. 87
      tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

6
src/ImageProcessorCore/Filters/Blend.cs

@ -73,5 +73,11 @@ namespace ImageProcessorCore.Filters
}
});
}
/// <inheritdoc/>
protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle)
{
this.toBlend?.Dispose();
}
}
}

2
src/ImageProcessorCore/Formats/Png/PngEncoder.cs

@ -18,7 +18,7 @@ namespace ImageProcessorCore.Formats
/// <summary>
/// Gets or sets the quality of output for images.
/// </summary>
public int Quality { get; set; } = int.MaxValue;
public int Quality { get; set; }
/// <inheritdoc/>
public string MimeType => "image/png";

2
src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs

@ -35,7 +35,7 @@ namespace ImageProcessorCore.Formats
/// <summary>
/// Gets or sets the quality of output for images.
/// </summary>
public int Quality { get; set; } = int.MaxValue;
public int Quality { get; set; }
/// <summary>
/// The compression level 1-9.

2
src/ImageProcessorCore/IImageBase.cs

@ -17,7 +17,7 @@ namespace ImageProcessorCore
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
float[] Pixels { get; }

26
src/ImageProcessorCore/Image.cs

@ -45,7 +45,7 @@ namespace ImageProcessorCore
new BmpFormat(),
new JpegFormat(),
new PngFormat(),
new GifFormat(),
new GifFormat()
});
/// <summary>
@ -223,6 +223,30 @@ namespace ImageProcessorCore
encoder.Encode(this, stream);
}
/// <inheritdoc/>
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);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>

156
src/ImageProcessorCore/ImageBase.cs

@ -6,13 +6,39 @@
namespace ImageProcessorCore
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The base class of all images. Encapsulates the basic properties and methods
/// required to manipulate images.
/// </summary>
public abstract class ImageBase : IImageBase
public abstract unsafe class ImageBase : IImageBase, IDisposable
{
/// <summary>
/// The position of the first pixel in the bitmap.
/// </summary>
private float* pixelsBase;
/// <summary>
/// The array of pixels.
/// </summary>
private float[] pixelsArray;
private GCHandle pixelsHandle;
/// <summary>
/// A value indicating whether this instance of the given entity has been disposed.
/// </summary>
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
/// <remarks>
/// 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.
/// </remarks>
protected bool IsDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="ImageBase"/> class.
/// </summary>
@ -23,12 +49,8 @@ namespace ImageProcessorCore
/// <summary>
/// Initializes a new instance of the <see cref="ImageBase"/> class.
/// </summary>
/// <param name="width">
/// The width of the image in pixels.
/// </param>
/// <param name="height">
/// The height of the image in pixels.
/// </param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
@ -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();
}
/// <summary>
@ -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);
}
/// <inheritdoc/>
~ImageBase()
{
this.Dispose(false);
}
/// <summary>
@ -76,45 +109,25 @@ namespace ImageProcessorCore
/// </summary>
public static int MaxHeight { get; set; } = int.MaxValue;
/// <summary>
/// Gets the image pixels as byte array.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public float[] Pixels { get; private set; }
/// <inheritdoc/>
public float[] Pixels => this.pixelsArray;
/// <summary>
/// Gets the width in pixels.
/// </summary>
/// <inheritdoc/>
public int Width { get; private set; }
/// <summary>
/// Gets the height in pixels.
/// </summary>
/// <inheritdoc/>
public int Height { get; private set; }
/// <summary>
/// Gets the pixel ratio made up of the width and height.
/// </summary>
/// <inheritdoc/>
public double PixelRatio => (double)this.Width / this.Height;
/// <summary>
/// Gets the <see cref="Rectangle"/> representing the bounds of the image.
/// </summary>
/// <inheritdoc/>
public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height);
/// <inheritdoc/>
public int Quality { get; set; }
/// <summary>
/// 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.
/// </summary>
/// <inheritdoc/>
public int FrameDelay { get; set; }
/// <inheritdoc/>
@ -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();
}
/// <inheritdoc/>
@ -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);
}
/// <inheritdoc/>
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);
}
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">If true, the object gets disposed.</param>
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;
}
}
}

1
src/ImageProcessorCore/ImageExtensions.cs

@ -164,6 +164,7 @@ namespace ImageProcessorCore
}
}
source.Dispose();
return transformedImage;
}
}

40
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);
}
}

25
src/ImageProcessorCore/Samplers/EntropyCrop.cs

@ -42,20 +42,21 @@ namespace ImageProcessorCore.Samplers
/// <inheritdoc/>
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;
}
}
/// <inheritdoc/>
@ -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,

2
src/ImageProcessorCore/Samplers/Resize.cs

@ -164,6 +164,8 @@ namespace ImageProcessorCore.Samplers
{
target.ClonePixels(target.Width, target.Height, source.Pixels);
}
this.firstPass?.Dispose();
}
}
}

2
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)

23
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");

120
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);
}
}
}
}
}

11
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());
}
}
}
}

15
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");
}
}

87
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);
}
}
}
}

Loading…
Cancel
Save