Browse Source

Merge pull request #97 from JimBobSquarePants/IDisposable

Make all images implement IDisposable
af/merge-core
James Jackson-South 9 years ago
committed by GitHub
parent
commit
7037736f73
  1. 2
      src/ImageSharp.Drawing/project.json
  2. 18
      src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs
  3. 2
      src/ImageSharp.Formats.Bmp/project.json
  4. 2
      src/ImageSharp.Formats.Gif/project.json
  5. 8
      src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
  6. 1
      src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs
  7. 2
      src/ImageSharp.Formats.Jpeg/project.json
  8. 2
      src/ImageSharp.Formats.Png/project.json
  9. 109
      src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs
  10. 78
      src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs
  11. 83
      src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs
  12. 94
      src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
  13. 127
      src/ImageSharp.Processing/Processors/Effects/OilPaintingProcessor.cs
  14. 67
      src/ImageSharp.Processing/Processors/Effects/PixelateProcessor.cs
  15. 141
      src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs
  16. 32
      src/ImageSharp.Processing/Processors/Transforms/CropProcessor.cs
  17. 26
      src/ImageSharp.Processing/Processors/Transforms/EntropyCropProcessor.cs
  18. 72
      src/ImageSharp.Processing/Processors/Transforms/FlipProcessor.cs
  19. 141
      src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs
  20. 140
      src/ImageSharp.Processing/Processors/Transforms/RotateProcessor.cs
  21. 35
      src/ImageSharp.Processing/Processors/Transforms/SkewProcessor.cs
  22. 5
      src/ImageSharp.Processing/project.json
  23. 33
      src/ImageSharp/Image/IImageBase{TColor}.cs
  24. 130
      src/ImageSharp/Image/ImageBase{TColor}.cs
  25. 16
      src/ImageSharp/Image/Image{TColor}.cs
  26. 145
      src/ImageSharp/Image/PixelAccessor{TColor}.cs
  27. 42
      src/ImageSharp/Image/PixelPool{TColor}.cs
  28. 30
      src/ImageSharp/Quantizers/Quantize.cs
  29. 2
      src/ImageSharp/project.json
  30. 18
      tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs
  31. 24
      tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs
  32. 24
      tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs
  33. 23
      tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs
  34. 29
      tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs
  35. 12
      tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs
  36. 34
      tests/ImageSharp.Benchmarks/Image/CopyPixels.cs
  37. 6
      tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs
  38. 17
      tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs
  39. 6
      tests/ImageSharp.Benchmarks/Image/DecodeGif.cs
  40. 6
      tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs
  41. 6
      tests/ImageSharp.Benchmarks/Image/DecodePng.cs
  42. 8
      tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs
  43. 4
      tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs
  44. 8
      tests/ImageSharp.Benchmarks/Image/EncodeGif.cs
  45. 8
      tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs
  46. 8
      tests/ImageSharp.Benchmarks/Image/EncodePng.cs
  47. 10
      tests/ImageSharp.Benchmarks/Image/GetSetPixel.cs
  48. 8
      tests/ImageSharp.Benchmarks/Samplers/Crop.cs
  49. 6
      tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs
  50. 16
      tests/ImageSharp.Benchmarks/Samplers/Resize.cs
  51. 137
      tests/ImageSharp.Tests/Drawing/BeziersTests.cs
  52. 21
      tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
  53. 101
      tests/ImageSharp.Tests/Drawing/DrawPathTests.cs
  54. 71
      tests/ImageSharp.Tests/Drawing/FillPatternTests.cs
  55. 100
      tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs
  56. 226
      tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs
  57. 155
      tests/ImageSharp.Tests/Drawing/LineTests.cs
  58. 112
      tests/ImageSharp.Tests/Drawing/PolygonTests.cs
  59. 32
      tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs
  60. 102
      tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs
  61. 138
      tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs
  62. 156
      tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs
  63. 15
      tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs
  64. 105
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  65. 16
      tests/ImageSharp.Tests/Formats/Jpg/BadEofJpegTests.cs
  66. 61
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  67. 44
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  68. 85
      tests/ImageSharp.Tests/Formats/Jpg/JpegUtilsTests.cs
  69. 4
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs
  70. 20
      tests/ImageSharp.Tests/Formats/Png/PngTests.cs
  71. 9
      tests/ImageSharp.Tests/Image/ImageTests.cs
  72. 118
      tests/ImageSharp.Tests/Image/PixelAccessorTests.cs
  73. 74
      tests/ImageSharp.Tests/Image/PixelPoolTests.cs
  74. 20
      tests/ImageSharp.Tests/Processors/Filters/AlphaTest.cs
  75. 19
      tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs
  76. 8
      tests/ImageSharp.Tests/Processors/Filters/BackgroundColorTest.cs
  77. 10
      tests/ImageSharp.Tests/Processors/Filters/BinaryThreshold.cs
  78. 8
      tests/ImageSharp.Tests/Processors/Filters/BlackWhiteTest.cs
  79. 10
      tests/ImageSharp.Tests/Processors/Filters/BoxBlurTest.cs
  80. 10
      tests/ImageSharp.Tests/Processors/Filters/BrightnessTest.cs
  81. 10
      tests/ImageSharp.Tests/Processors/Filters/ColorBlindnessTest.cs
  82. 10
      tests/ImageSharp.Tests/Processors/Filters/ContrastTest.cs
  83. 8
      tests/ImageSharp.Tests/Processors/Filters/CropTest.cs
  84. 15
      tests/ImageSharp.Tests/Processors/Filters/DetectEdgesTest.cs
  85. 10
      tests/ImageSharp.Tests/Processors/Filters/EntropyCropTest.cs
  86. 10
      tests/ImageSharp.Tests/Processors/Filters/FlipTests.cs
  87. 10
      tests/ImageSharp.Tests/Processors/Filters/GaussianBlurTest.cs
  88. 10
      tests/ImageSharp.Tests/Processors/Filters/GaussianSharpenTest.cs
  89. 31
      tests/ImageSharp.Tests/Processors/Filters/GlowTest.cs
  90. 10
      tests/ImageSharp.Tests/Processors/Filters/GrayscaleTest.cs
  91. 10
      tests/ImageSharp.Tests/Processors/Filters/HueTest.cs
  92. 16
      tests/ImageSharp.Tests/Processors/Filters/InvertTest.cs
  93. 8
      tests/ImageSharp.Tests/Processors/Filters/KodachromeTest.cs
  94. 15
      tests/ImageSharp.Tests/Processors/Filters/LomographTest.cs
  95. 21
      tests/ImageSharp.Tests/Processors/Filters/OilPaintTest.cs
  96. 8
      tests/ImageSharp.Tests/Processors/Filters/PadTest.cs
  97. 8
      tests/ImageSharp.Tests/Processors/Filters/PixelateTest.cs
  98. 8
      tests/ImageSharp.Tests/Processors/Filters/PolaroidTest.cs
  99. 76
      tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs
  100. 10
      tests/ImageSharp.Tests/Processors/Filters/RotateFlipTest.cs

2
src/ImageSharp.Drawing/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Drawing",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [

18
src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs

@ -34,7 +34,7 @@ namespace ImageSharp.Formats
/// <param name="bitsPerPixel">The <see cref="BmpBitsPerPixel"/></param>
public void Encode<TColor>(ImageBase<TColor> image, Stream stream, BmpBitsPerPixel bitsPerPixel)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
@ -119,23 +119,23 @@ namespace ImageSharp.Formats
/// Writes the pixel data to the binary stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="image">
/// The <see cref="ImageBase{TColor}"/> containing pixel data.
/// </param>
private void WriteImage<TColor>(EndianBinaryWriter writer, ImageBase<TColor> image)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
{
using (PixelAccessor<TColor> pixels = image.Lock())
{
switch (this.bmpBitsPerPixel)
{
case BmpBitsPerPixel.Pixel32:
this.Write32Bit<TColor>(writer, pixels);
this.Write32Bit(writer, pixels);
break;
case BmpBitsPerPixel.Pixel24:
this.Write24Bit<TColor>(writer, pixels);
this.Write24Bit(writer, pixels);
break;
}
}
@ -145,11 +145,11 @@ namespace ImageSharp.Formats
/// Writes the 32bit color palette to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="pixels">The <see cref="PixelAccessor{TColor}"/> containing pixel data.</param>
private void Write32Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
{
using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.Zyxw, this.padding))
{
for (int y = pixels.Height - 1; y >= 0; y--)
@ -164,11 +164,11 @@ namespace ImageSharp.Formats
/// Writes the 24bit color palette to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="pixels">The <see cref="PixelAccessor{TColor}"/> containing pixel data.</param>
private void Write24Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
{
using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.Zyx, this.padding))
{
for (int y = pixels.Height - 1; y >= 0; y--)

2
src/ImageSharp.Formats.Bmp/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Formats.Bmp",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [

2
src/ImageSharp.Formats.Gif/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Formats.Gif",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [

8
src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs

@ -5,10 +5,8 @@
namespace ImageSharp.Formats
{
using System;
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageSharp.Formats.Jpg;
@ -586,7 +584,7 @@ namespace ImageSharp.Formats
byte yellow = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
TColor packed = default(TColor);
this.PackCmyk<TColor>(ref packed, cyan, magenta, yellow, x, y);
this.PackCmyk(ref packed, cyan, magenta, yellow, x, y);
pixels[x, y] = packed;
}
});
@ -744,7 +742,7 @@ namespace ImageSharp.Formats
byte cr = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
TColor packed = default(TColor);
this.PackYcck<TColor>(ref packed, yy, cb, cr, x, y);
this.PackYcck(ref packed, yy, cb, cr, x, y);
pixels[x, y] = packed;
}
});
@ -1037,7 +1035,7 @@ namespace ImageSharp.Formats
}
this.InputProcessor.ReadFull(this.Temp, 0, remaining);
this.RestartInterval = ((int)this.Temp[0] << 8) + (int)this.Temp[1];
this.RestartInterval = (this.Temp[0] << 8) + this.Temp[1];
}
/// <summary>

1
src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs

@ -8,7 +8,6 @@ namespace ImageSharp.Formats
using System;
using System.Buffers;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Formats.Jpg;

2
src/ImageSharp.Formats.Jpeg/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Formats.Jpeg",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [

2
src/ImageSharp.Formats.Png/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Formats.Png",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [

109
src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs

@ -54,73 +54,74 @@ namespace ImageSharp.Processing.Processors
int maxY = endY - 1;
int maxX = endX - 1;
TColor[] target = new TColor[source.Width * source.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(source.Width, source.Height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(source.Width, source.Height))
{
Parallel.For(
startY,
endY,
this.ParallelOptions,
y =>
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
for (int x = startX; x < endX; x++)
Parallel.For(
startY,
endY,
this.ParallelOptions,
y =>
{
float rX = 0;
float gX = 0;
float bX = 0;
float rY = 0;
float gY = 0;
float bY = 0;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelYHeight; fy++)
for (int x = startX; x < endX; x++)
{
int fyr = fy - radiusY;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
for (int fx = 0; fx < kernelXWidth; fx++)
float rX = 0;
float gX = 0;
float bX = 0;
float rY = 0;
float gY = 0;
float bY = 0;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelYHeight; fy++)
{
int fxr = fx - radiusX;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
int fyr = fy - radiusY;
int offsetY = y + fyr;
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
float r = currentColor.X;
float g = currentColor.Y;
float b = currentColor.Z;
if (fy < kernelXHeight)
{
rX += this.KernelX[fy][fx] * r;
gX += this.KernelX[fy][fx] * g;
bX += this.KernelX[fy][fx] * b;
}
offsetY = offsetY.Clamp(0, maxY);
if (fx < kernelYWidth)
for (int fx = 0; fx < kernelXWidth; fx++)
{
rY += this.KernelY[fy][fx] * r;
gY += this.KernelY[fy][fx] * g;
bY += this.KernelY[fy][fx] * b;
int fxr = fx - radiusX;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
float r = currentColor.X;
float g = currentColor.Y;
float b = currentColor.Z;
if (fy < kernelXHeight)
{
rX += this.KernelX[fy][fx] * r;
gX += this.KernelX[fy][fx] * g;
bX += this.KernelX[fy][fx] * b;
}
if (fx < kernelYWidth)
{
rY += this.KernelY[fy][fx] * r;
gY += this.KernelY[fy][fx] * g;
bY += this.KernelY[fy][fx] * b;
}
}
}
}
float red = (float)Math.Sqrt((rX * rX) + (rY * rY));
float green = (float)Math.Sqrt((gX * gX) + (gY * gY));
float blue = (float)Math.Sqrt((bX * bX) + (bY * bY));
float red = (float)Math.Sqrt((rX * rX) + (rY * rY));
float green = (float)Math.Sqrt((gX * gX) + (gY * gY));
float blue = (float)Math.Sqrt((bX * bX) + (bY * bY));
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
}
});
}
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
}
});
}
source.SetPixels(source.Width, source.Height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

78
src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs

@ -45,13 +45,17 @@ namespace ImageSharp.Processing.Processors
int width = source.Width;
int height = source.Height;
TColor[] target = new TColor[width * height];
TColor[] firstPass = new TColor[width * height];
this.ApplyConvolution(width, height, firstPass, source.Pixels, sourceRectangle, kernelX);
this.ApplyConvolution(width, height, target, firstPass, sourceRectangle, kernelY);
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
using (PixelAccessor<TColor> firstPassPixels = new PixelAccessor<TColor>(width, height))
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
this.ApplyConvolution(width, height, firstPassPixels, sourcePixels, sourceRectangle, kernelX);
this.ApplyConvolution(width, height, targetPixels, firstPassPixels, sourceRectangle, kernelY);
}
source.SetPixels(width, height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
/// <summary>
@ -60,13 +64,13 @@ namespace ImageSharp.Processing.Processors
/// </summary>
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="target">The target pixels to apply the process to.</param>
/// <param name="source">The source pixels. Cannot be null.</param>
/// <param name="targetPixels">The target pixels to apply the process to.</param>
/// <param name="sourcePixels">The source pixels. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <param name="kernel">The kernel operator.</param>
private void ApplyConvolution(int width, int height, TColor[] target, TColor[] source, Rectangle sourceRectangle, float[][] kernel)
private void ApplyConvolution(int width, int height, PixelAccessor<TColor> targetPixels, PixelAccessor<TColor> sourcePixels, Rectangle sourceRectangle, float[][] kernel)
{
int kernelHeight = kernel.Length;
int kernelWidth = kernel[0].Length;
@ -80,45 +84,41 @@ namespace ImageSharp.Processing.Processors
int maxY = endY - 1;
int maxX = endX - 1;
using (PixelAccessor<TColor> sourcePixels = source.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
Parallel.For(
startY,
endY,
this.ParallelOptions,
y =>
{
Parallel.For(
startY,
endY,
this.ParallelOptions,
y =>
for (int x = startX; x < endX; x++)
{
for (int x = startX; x < endX; x++)
{
Vector4 destination = default(Vector4);
Vector4 destination = default(Vector4);
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelHeight; fy++)
{
int fyr = fy - radiusY;
int offsetY = y + fyr;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelHeight; fy++)
{
int fyr = fy - radiusY;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
offsetY = offsetY.Clamp(0, maxY);
for (int fx = 0; fx < kernelWidth; fx++)
{
int fxr = fx - radiusX;
int offsetX = x + fxr;
for (int fx = 0; fx < kernelWidth; fx++)
{
int fxr = fx - radiusX;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
destination += kernel[fy][fx] * currentColor;
}
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
destination += kernel[fy][fx] * currentColor;
}
TColor packed = default(TColor);
packed.PackFromVector4(destination);
targetPixels[x, y] = packed;
}
});
}
TColor packed = default(TColor);
packed.PackFromVector4(destination);
targetPixels[x, y] = packed;
}
});
}
}
}

83
src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs

@ -44,60 +44,61 @@ namespace ImageSharp.Processing.Processors
int maxY = endY - 1;
int maxX = endX - 1;
TColor[] target = new TColor[source.Width * source.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(source.Width, source.Height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(source.Width, source.Height))
{
Parallel.For(
startY,
endY,
this.ParallelOptions,
y =>
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
for (int x = startX; x < endX; x++)
Parallel.For(
startY,
endY,
this.ParallelOptions,
y =>
{
float rX = 0;
float gX = 0;
float bX = 0;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelLength; fy++)
for (int x = startX; x < endX; x++)
{
int fyr = fy - radius;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
float rX = 0;
float gX = 0;
float bX = 0;
for (int fx = 0; fx < kernelLength; fx++)
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelLength; fy++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
int fyr = fy - radius;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
for (int fx = 0; fx < kernelLength; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
float r = currentColor.X;
float g = currentColor.Y;
float b = currentColor.Z;
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
float r = currentColor.X;
float g = currentColor.Y;
float b = currentColor.Z;
rX += kernelX[fy][fx] * r;
gX += kernelX[fy][fx] * g;
bX += kernelX[fy][fx] * b;
rX += kernelX[fy][fx] * r;
gX += kernelX[fy][fx] * g;
bX += kernelX[fy][fx] * b;
}
}
}
float red = rX;
float green = gX;
float blue = bX;
float red = rX;
float green = gX;
float blue = bX;
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
}
});
}
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
}
});
}
source.SetPixels(source.Width, source.Height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

94
src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs

@ -75,64 +75,62 @@ namespace ImageSharp.Processing.Processors
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// First run.
ImageBase<TColor> target = new Image<TColor>(source.Width, source.Height);
target.ClonePixels(source.Width, source.Height, source.Pixels);
new ConvolutionProcessor<TColor>(kernels[0]).Apply(target, sourceRectangle);
if (kernels.Length == 1)
// we need a clean copy for each pass to start from
using (ImageBase<TColor> cleanCopy = new Image<TColor>(source))
{
return;
}
new ConvolutionProcessor<TColor>(kernels[0]).Apply(source, sourceRectangle);
int shiftY = startY;
int shiftX = startX;
// Reset offset if necessary.
if (minX > 0)
{
shiftX = 0;
}
if (kernels.Length == 1)
{
return;
}
if (minY > 0)
{
shiftY = 0;
}
int shiftY = startY;
int shiftX = startX;
// Additional runs.
// ReSharper disable once ForCanBeConvertedToForeach
for (int i = 1; i < kernels.Length; i++)
{
// Create a clone for each pass and copy the offset pixels across.
ImageBase<TColor> pass = new Image<TColor>(source.Width, source.Height);
pass.ClonePixels(source.Width, source.Height, source.Pixels);
// Reset offset if necessary.
if (minX > 0)
{
shiftX = 0;
}
new ConvolutionProcessor<TColor>(kernels[i]).Apply(pass, sourceRectangle);
if (minY > 0)
{
shiftY = 0;
}
using (PixelAccessor<TColor> passPixels = pass.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock())
// Additional runs.
// ReSharper disable once ForCanBeConvertedToForeach
for (int i = 1; i < kernels.Length; i++)
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
using (ImageBase<TColor> pass = new Image<TColor>(cleanCopy))
{
new ConvolutionProcessor<TColor>(kernels[i]).Apply(pass, sourceRectangle);
using (PixelAccessor<TColor> passPixels = pass.Lock())
using (PixelAccessor<TColor> targetPixels = source.Lock())
{
int offsetY = y - shiftY;
for (int x = minX; x < maxX; x++)
{
int offsetX = x - shiftX;
// Grab the max components of the two pixels
TColor packed = default(TColor);
packed.PackFromVector4(Vector4.Max(passPixels[offsetX, offsetY].ToVector4(), targetPixels[offsetX, offsetY].ToVector4()));
targetPixels[offsetX, offsetY] = packed;
}
});
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
int offsetY = y - shiftY;
for (int x = minX; x < maxX; x++)
{
int offsetX = x - shiftX;
// Grab the max components of the two pixels
TColor packed = default(TColor);
packed.PackFromVector4(Vector4.Max(passPixels[offsetX, offsetY].ToVector4(), targetPixels[offsetX, offsetY].ToVector4()));
targetPixels[offsetX, offsetY] = packed;
}
});
}
}
}
}
source.SetPixels(source.Width, source.Height, target.Pixels);
}
/// <inheritdoc/>

127
src/ImageSharp.Processing/Processors/Effects/OilPaintingProcessor.cs

@ -67,91 +67,92 @@ namespace ImageSharp.Processing.Processors
startX = 0;
}
TColor[] target = new TColor[source.Width * source.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(source.Width, source.Height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(source.Width, source.Height))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
for (int x = startX; x < endX; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
int maxIntensity = 0;
int maxIndex = 0;
int[] intensityBin = new int[levels];
float[] redBin = new float[levels];
float[] blueBin = new float[levels];
float[] greenBin = new float[levels];
for (int fy = 0; fy <= radius; fy++)
for (int x = startX; x < endX; x++)
{
int fyr = fy - radius;
int offsetY = y + fyr;
// Skip the current row
if (offsetY < minY)
{
continue;
}
int maxIntensity = 0;
int maxIndex = 0;
// Outwith the current bounds so break.
if (offsetY >= maxY)
{
break;
}
int[] intensityBin = new int[levels];
float[] redBin = new float[levels];
float[] blueBin = new float[levels];
float[] greenBin = new float[levels];
for (int fx = 0; fx <= radius; fx++)
for (int fy = 0; fy <= radius; fy++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
int fyr = fy - radius;
int offsetY = y + fyr;
// Skip the column
if (offsetX < 0)
// Skip the current row
if (offsetY < minY)
{
continue;
}
if (offsetX < maxX)
// Outwith the current bounds so break.
if (offsetY >= maxY)
{
// ReSharper disable once AccessToDisposedClosure
Vector4 color = sourcePixels[offsetX, offsetY].ToVector4();
float sourceRed = color.X;
float sourceBlue = color.Z;
float sourceGreen = color.Y;
break;
}
int currentIntensity = (int)Math.Round((sourceBlue + sourceGreen + sourceRed) / 3.0 * (levels - 1));
for (int fx = 0; fx <= radius; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
intensityBin[currentIntensity] += 1;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
// Skip the column
if (offsetX < 0)
{
continue;
}
if (intensityBin[currentIntensity] > maxIntensity)
if (offsetX < maxX)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
// ReSharper disable once AccessToDisposedClosure
Vector4 color = sourcePixels[offsetX, offsetY].ToVector4();
float sourceRed = color.X;
float sourceBlue = color.Z;
float sourceGreen = color.Y;
int currentIntensity = (int)Math.Round((sourceBlue + sourceGreen + sourceRed) / 3.0 * (levels - 1));
intensityBin[currentIntensity] += 1;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
if (intensityBin[currentIntensity] > maxIntensity)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
}
}
}
}
float red = Math.Abs(redBin[maxIndex] / maxIntensity);
float green = Math.Abs(greenBin[maxIndex] / maxIntensity);
float blue = Math.Abs(blueBin[maxIndex] / maxIntensity);
float red = Math.Abs(redBin[maxIndex] / maxIntensity);
float green = Math.Abs(greenBin[maxIndex] / maxIntensity);
float blue = Math.Abs(blueBin[maxIndex] / maxIntensity);
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
}
}
}
});
}
});
}
source.SetPixels(source.Width, source.Height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

67
src/ImageSharp.Processing/Processors/Effects/PixelateProcessor.cs

@ -63,51 +63,52 @@ namespace ImageSharp.Processing.Processors
// Get the range on the y-plane to choose from.
IEnumerable<int> range = EnumerableExtensions.SteppedRange(minY, i => i < maxY, size);
TColor[] target = new TColor[source.Width * source.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(source.Width, source.Height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(source.Width, source.Height))
{
Parallel.ForEach(
range,
this.ParallelOptions,
y =>
{
int offsetY = y - startY;
int offsetPy = offset;
for (int x = minX; x < maxX; x += size)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.ForEach(
range,
this.ParallelOptions,
y =>
{
int offsetX = x - startX;
int offsetPx = offset;
int offsetY = y - startY;
int offsetPy = offset;
// Make sure that the offset is within the boundary of the image.
while (offsetY + offsetPy >= maxY)
for (int x = minX; x < maxX; x += size)
{
offsetPy--;
}
int offsetX = x - startX;
int offsetPx = offset;
while (x + offsetPx >= maxX)
{
offsetPx--;
}
// Make sure that the offset is within the boundary of the image.
while (offsetY + offsetPy >= maxY)
{
offsetPy--;
}
// Get the pixel color in the centre of the soon to be pixelated area.
// ReSharper disable AccessToDisposedClosure
TColor pixel = sourcePixels[offsetX + offsetPx, offsetY + offsetPy];
while (x + offsetPx >= maxX)
{
offsetPx--;
}
// For each pixel in the pixelate size, set it to the centre color.
for (int l = offsetY; l < offsetY + size && l < maxY; l++)
{
for (int k = offsetX; k < offsetX + size && k < maxX; k++)
// Get the pixel color in the centre of the soon to be pixelated area.
// ReSharper disable AccessToDisposedClosure
TColor pixel = sourcePixels[offsetX + offsetPx, offsetY + offsetPy];
// For each pixel in the pixelate size, set it to the centre color.
for (int l = offsetY; l < offsetY + size && l < maxY; l++)
{
targetPixels[k, l] = pixel;
for (int k = offsetX; k < offsetX + size && k < maxX; k++)
{
targetPixels[k, l] = pixel;
}
}
}
}
});
});
source.SetPixels(source.Width, source.Height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

141
src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs

@ -66,103 +66,104 @@ namespace ImageSharp.Processing.Processors
int minY = Math.Max(0, startY);
int maxY = Math.Min(height, endY);
TColor[] target = new TColor[width * height];
if (this.Sampler is NearestNeighborResampler)
{
// Scaling factors
float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = minX; x < maxX; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
});
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = minX; x < maxX; x++)
{
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
});
}
// Break out now.
source.SwapPixelsBuffers(targetPixels);
return;
}
// Break out now.
source.SetPixels(width, height, target);
return;
}
// Interpolate the image using the calculated weights.
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
TColor[] firstPass = new TColor[width * source.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> firstPassPixels = firstPass.Lock<TColor>(width, source.Height))
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
sourceRectangle.Height,
this.ParallelOptions,
y =>
{
for (int x = minX; x < maxX; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> firstPassPixels = new PixelAccessor<TColor>(width, source.Height))
{
Parallel.For(
0,
sourceRectangle.Height,
this.ParallelOptions,
y =>
{
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
for (int x = minX; x < maxX; x++)
{
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
// Destination color components
Vector4 destination = Vector4.Zero;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4().Expand() * xw.Value;
}
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4().Expand() * xw.Value;
}
TColor d = default(TColor);
d.PackFromVector4(destination.Compress());
firstPassPixels[x, y] = d;
}
});
// Now process the rows.
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
TColor d = default(TColor);
d.PackFromVector4(destination.Compress());
firstPassPixels[x, y] = d;
}
});
for (int x = 0; x < width; x++)
// Now process the rows.
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Destination color components
Vector4 destination = Vector4.Zero;
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
for (int i = 0; i < verticalValues.Length; i++)
for (int x = 0; x < width; x++)
{
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4().Expand() * yw.Value;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < verticalValues.Length; i++)
{
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4().Expand() * yw.Value;
}
TColor d = default(TColor);
d.PackFromVector4(destination.Compress());
targetPixels[x, y] = d;
}
});
}
TColor d = default(TColor);
d.PackFromVector4(destination.Compress());
targetPixels[x, y] = d;
}
});
source.SwapPixelsBuffers(targetPixels);
}
source.SetPixels(width, height, target);
}
}
}

32
src/ImageSharp.Processing/Processors/Transforms/CropProcessor.cs

@ -42,25 +42,25 @@ namespace ImageSharp.Processing.Processors
int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X);
int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right);
TColor[] target = new TColor[this.CropRectangle.Width * this.CropRectangle.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(this.CropRectangle.Width, this.CropRectangle.Height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(this.CropRectangle.Width, this.CropRectangle.Height))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
for (int x = minX; x < maxX; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
targetPixels[x - minX, y - minY] = sourcePixels[x, y];
}
});
}
for (int x = minX; x < maxX; x++)
{
targetPixels[x - minX, y - minY] = sourcePixels[x, y];
}
});
}
source.SetPixels(this.CropRectangle.Width, this.CropRectangle.Height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

26
src/ImageSharp.Processing/Processors/Transforms/EntropyCropProcessor.cs

@ -36,24 +36,24 @@ namespace ImageSharp.Processing.Processors
/// <inheritdoc/>
protected override void OnApply(ImageBase<TColor> source, Rectangle sourceRectangle)
{
ImageBase<TColor> temp = new Image<TColor>(source.Width, source.Height);
temp.ClonePixels(source.Width, source.Height, source.Pixels);
using (ImageBase<TColor> temp = new Image<TColor>(source))
{
// Detect the edges.
new SobelProcessor<TColor>().Apply(temp, sourceRectangle);
// Detect the edges.
new SobelProcessor<TColor>().Apply(temp, sourceRectangle);
// Apply threshold binarization filter.
new BinaryThresholdProcessor<TColor>(this.Value).Apply(temp, sourceRectangle);
// Apply threshold binarization filter.
new BinaryThresholdProcessor<TColor>(this.Value).Apply(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);
if (rectangle == sourceRectangle)
{
return;
}
if (rectangle == sourceRectangle)
{
return;
new CropProcessor<TColor>(rectangle).Apply(source, sourceRectangle);
}
new CropProcessor<TColor>(rectangle).Apply(source, sourceRectangle);
}
}
}

72
src/ImageSharp.Processing/Processors/Transforms/FlipProcessor.cs

@ -55,27 +55,27 @@ namespace ImageSharp.Processing.Processors
int height = source.Height;
int halfHeight = (int)Math.Ceiling(source.Height * .5F);
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
halfHeight,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
halfHeight,
this.ParallelOptions,
y =>
{
int newY = height - y - 1;
targetPixels[x, y] = sourcePixels[x, newY];
targetPixels[x, newY] = sourcePixels[x, y];
}
});
}
for (int x = 0; x < width; x++)
{
int newY = height - y - 1;
targetPixels[x, y] = sourcePixels[x, newY];
targetPixels[x, newY] = sourcePixels[x, y];
}
});
}
source.SetPixels(width, height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
/// <summary>
@ -89,27 +89,27 @@ namespace ImageSharp.Processing.Processors
int height = source.Height;
int halfWidth = (int)Math.Ceiling(width * .5F);
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < halfWidth; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
int newX = width - x - 1;
targetPixels[x, y] = sourcePixels[newX, y];
targetPixels[newX, y] = sourcePixels[x, y];
}
});
}
for (int x = 0; x < halfWidth; x++)
{
int newX = width - x - 1;
targetPixels[x, y] = sourcePixels[newX, y];
targetPixels[newX, y] = sourcePixels[x, y];
}
});
}
source.SetPixels(width, height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

141
src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs

@ -65,103 +65,104 @@ namespace ImageSharp.Processing.Processors
int minY = Math.Max(0, startY);
int maxY = Math.Min(height, endY);
TColor[] target = new TColor[width * height];
if (this.Sampler is NearestNeighborResampler)
{
// Scaling factors
float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = minX; x < maxX; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
});
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = minX; x < maxX; x++)
{
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
});
}
// Break out now.
source.SwapPixelsBuffers(targetPixels);
return;
}
// Break out now.
source.SetPixels(width, height, target);
return;
}
// Interpolate the image using the calculated weights.
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
TColor[] firstPass = new TColor[width * source.Height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> firstPassPixels = firstPass.Lock<TColor>(width, source.Height))
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
sourceRectangle.Height,
this.ParallelOptions,
y =>
{
for (int x = minX; x < maxX; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> firstPassPixels = new PixelAccessor<TColor>(width, source.Height))
{
Parallel.For(
0,
sourceRectangle.Height,
this.ParallelOptions,
y =>
{
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
for (int x = minX; x < maxX; x++)
{
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
// Destination color components
Vector4 destination = Vector4.Zero;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4() * xw.Value;
}
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4() * xw.Value;
}
TColor d = default(TColor);
d.PackFromVector4(destination);
firstPassPixels[x, y] = d;
}
});
// Now process the rows.
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
TColor d = default(TColor);
d.PackFromVector4(destination);
firstPassPixels[x, y] = d;
}
});
for (int x = 0; x < width; x++)
// Now process the rows.
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Destination color components
Vector4 destination = Vector4.Zero;
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
for (int i = 0; i < verticalValues.Length; i++)
for (int x = 0; x < width; x++)
{
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4() * yw.Value;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < verticalValues.Length; i++)
{
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4() * yw.Value;
}
TColor d = default(TColor);
d.PackFromVector4(destination);
targetPixels[x, y] = d;
}
});
}
TColor d = default(TColor);
d.PackFromVector4(destination);
targetPixels[x, y] = d;
}
});
source.SwapPixelsBuffers(targetPixels);
}
source.SetPixels(width, height, target);
}
}
}

140
src/ImageSharp.Processing/Processors/Transforms/RotateProcessor.cs

@ -42,29 +42,30 @@ namespace ImageSharp.Processing.Processors
int height = this.CanvasRectangle.Height;
int width = this.CanvasRectangle.Width;
Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix);
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
Point transformedPoint = Point.Rotate(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
for (int x = 0; x < width; x++)
{
targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
Point transformedPoint = Point.Rotate(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
{
targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
}
}
}
});
}
});
}
source.SetPixels(width, height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
/// <inheritdoc/>
@ -124,28 +125,29 @@ namespace ImageSharp.Processing.Processors
{
int width = source.Width;
int height = source.Height;
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(height, width))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(height, width))
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
int newX = height - y - 1;
newX = height - newX - 1;
int newY = width - x - 1;
targetPixels[newX, newY] = sourcePixels[x, y];
}
});
}
for (int x = 0; x < width; x++)
{
int newX = height - y - 1;
newX = height - newX - 1;
int newY = width - x - 1;
targetPixels[newX, newY] = sourcePixels[x, y];
}
});
}
source.SetPixels(height, width, target);
source.SwapPixelsBuffers(targetPixels);
}
}
/// <summary>
@ -156,27 +158,28 @@ namespace ImageSharp.Processing.Processors
{
int width = source.Width;
int height = source.Height;
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
int newX = width - x - 1;
int newY = height - y - 1;
targetPixels[newX, newY] = sourcePixels[x, y];
}
});
}
for (int x = 0; x < width; x++)
{
int newX = width - x - 1;
int newY = height - y - 1;
targetPixels[newX, newY] = sourcePixels[x, y];
}
});
}
source.SetPixels(width, height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
/// <summary>
@ -187,26 +190,27 @@ namespace ImageSharp.Processing.Processors
{
int width = source.Width;
int height = source.Height;
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(height, width))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(height, width))
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
int newX = height - y - 1;
targetPixels[newX, x] = sourcePixels[x, y];
}
});
}
for (int x = 0; x < width; x++)
{
int newX = height - y - 1;
targetPixels[newX, x] = sourcePixels[x, y];
}
});
}
source.SetPixels(height, width, target);
source.SwapPixelsBuffers(targetPixels);
}
}
}
}

35
src/ImageSharp.Processing/Processors/Transforms/SkewProcessor.cs

@ -42,29 +42,30 @@ namespace ImageSharp.Processing.Processors
int height = this.CanvasRectangle.Height;
int width = this.CanvasRectangle.Width;
Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix);
TColor[] target = new TColor[width * height];
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PixelAccessor<TColor> targetPixels = target.Lock<TColor>(width, height))
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
for (int x = 0; x < width; x++)
using (PixelAccessor<TColor> sourcePixels = source.Lock())
{
Parallel.For(
0,
height,
this.ParallelOptions,
y =>
{
Point transformedPoint = Point.Skew(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
for (int x = 0; x < width; x++)
{
targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
Point transformedPoint = Point.Skew(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
{
targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
}
}
}
});
}
});
}
source.SetPixels(width, height, target);
source.SwapPixelsBuffers(targetPixels);
}
}
/// <inheritdoc/>

5
src/ImageSharp.Processing/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp.Processing",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [
@ -39,8 +39,7 @@
},
"dependencies": {
"ImageSharp": {
"target": "project",
"version": "1.0.0-alpha1"
"target": "project"
},
"StyleCop.Analyzers": {
"version": "1.1.0-beta001",

33
src/ImageSharp/Image/IImageBase{TColor}.cs

@ -11,11 +11,13 @@ namespace ImageSharp
/// Encapsulates the basic properties and methods required to manipulate images in varying formats.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public interface IImageBase<TColor> : IImageBase
public interface IImageBase<TColor> : IImageBase, IDisposable
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
/// <summary>
/// Gets the pixels as an array of the given packed pixel format.
/// Important. Due to the nature in the way this is constructed do not rely on the length
/// of the array for calculations. Use Width * Height.
/// </summary>
TColor[] Pixels { get; }
@ -29,35 +31,6 @@ namespace ImageSharp
/// </exception>
void InitPixels(int width, int height);
/// <summary>
/// Sets the pixel array of the image to the given value.
/// </summary>
/// <param name="width">The new width of the image. Must be greater than zero.</param>
/// <param name="height">The new height of the image. Must be greater than zero.</param>
/// <param name="pixels">The array with pixels. Must be a multiple of the width and height.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
/// <exception cref="System.ArgumentException">
/// Thrown if the <paramref name="pixels"/> length is not equal to Width * Height.
/// </exception>
void SetPixels(int width, int height, TColor[] pixels);
/// <summary>
/// Sets the pixel array of the image to the given value, creating a copy of
/// the original pixels.
/// </summary>
/// <param name="width">The new width of the image. Must be greater than zero.</param>
/// <param name="height">The new height of the image. Must be greater than zero.</param>
/// <param name="pixels">The array with pixels. Must be a multiple of four times the width and height.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
/// <exception cref="System.ArgumentException">
/// Thrown if the <paramref name="pixels"/> length is not equal to Width * Height.
/// </exception>
void ClonePixels(int width, int height, TColor[] pixels);
/// <summary>
/// Locks the image providing access to the pixels.
/// <remarks>

130
src/ImageSharp/Image/ImageBase{TColor}.cs

@ -22,6 +22,17 @@ namespace ImageSharp
/// </summary>
private TColor[] pixelBuffer;
/// <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>
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="ImageBase{TColor}"/> class.
/// </summary>
@ -41,7 +52,7 @@ namespace ImageSharp
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
protected ImageBase(int width, int height, Configuration configuration = null)
@ -67,11 +78,12 @@ namespace ImageSharp
this.Height = other.Height;
this.CopyProperties(other);
// Copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here.
this.pixelBuffer = new TColor[this.Width * this.Height];
// Rent then copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here.
this.RentPixels();
using (PixelAccessor<TColor> sourcePixels = other.Lock())
using (PixelAccessor<TColor> target = this.Lock())
{
// Check we can do this without crashing
sourcePixels.CopyTo(target);
}
}
@ -108,58 +120,53 @@ namespace ImageSharp
/// </summary>
public Configuration Configuration { get; private set; }
/// <inheritdoc/>
public void InitPixels(int width, int height)
/// <inheritdoc />
public void Dispose()
{
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
this.Width = width;
this.Height = height;
this.pixelBuffer = new TColor[width * height];
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);
}
/// <inheritdoc/>
public void SetPixels(int width, int height, TColor[] pixels)
public void InitPixels(int width, int height)
{
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(pixels, nameof(pixels));
if (pixels.Length != width * height)
{
throw new ArgumentException("Pixel array must have the length of Width * Height.");
}
this.Width = width;
this.Height = height;
this.pixelBuffer = pixels;
this.RentPixels();
}
/// <inheritdoc/>
public void ClonePixels(int width, int height, TColor[] pixels)
public virtual PixelAccessor<TColor> Lock()
{
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(pixels, nameof(pixels));
if (pixels.Length != width * height)
{
throw new ArgumentException("Pixel array must have the length of Width * Height.");
}
this.Width = width;
this.Height = height;
// Copy the pixels. TODO: use Unsafe.Copy.
this.pixelBuffer = new TColor[pixels.Length];
Array.Copy(pixels, this.pixelBuffer, pixels.Length);
return new PixelAccessor<TColor>(this);
}
/// <inheritdoc/>
public virtual PixelAccessor<TColor> Lock()
/// <summary>
/// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer.
/// </summary>
/// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(PixelAccessor<TColor> pixelSource)
{
return new PixelAccessor<TColor>(this);
Guard.NotNull(pixelSource, nameof(pixelSource));
Guard.IsTrue(pixelSource.PooledMemory, nameof(pixelSource.PooledMemory), "pixelSource must be using pooled memory");
int newWidth = pixelSource.Width;
int newHeight = pixelSource.Height;
// Push my memory into the accessor (which in turn unpins the old puffer ready for the images use)
TColor[] newPixels = pixelSource.ReturnCurrentPixelsAndReplaceThemInternally(this.Width, this.Height, this.pixelBuffer, true);
this.Width = newWidth;
this.Height = newHeight;
this.pixelBuffer = newPixels;
}
/// <summary>
@ -174,5 +181,52 @@ namespace ImageSharp
this.Quality = other.Quality;
this.FrameDelay = other.FrameDelay;
}
/// <summary>
/// Releases any unmanaged resources from the inheriting class.
/// </summary>
protected virtual void ReleaseUnmanagedResources()
{
// TODO release unmanaged resources here
}
/// <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;
}
this.ReleaseUnmanagedResources();
if (disposing)
{
this.ReturnPixels();
}
// Note disposing is done.
this.isDisposed = true;
}
/// <summary>
/// Rents the pixel array from the pool.
/// </summary>
private void RentPixels()
{
this.pixelBuffer = PixelPool<TColor>.RentPixels(this.Width * this.Height);
}
/// <summary>
/// Returns the rented pixel array back to the pool.
/// </summary>
private void ReturnPixels()
{
PixelPool<TColor>.ReturnPixels(this.pixelBuffer);
this.pixelBuffer = null;
}
}
}

16
src/ImageSharp/Image/Image{TColor}.cs

@ -334,9 +334,9 @@ namespace ImageSharp
target.ExifProfile = new ExifProfile(this.ExifProfile);
}
foreach (ImageFrame<TColor> frame in this.Frames)
for (int i = 0; i < this.Frames.Count; i++)
{
target.Frames.Add(frame.To<TColor2>());
target.Frames.Add(this.Frames[i].To<TColor2>());
}
return target;
@ -372,6 +372,18 @@ namespace ImageSharp
return new ImageFrame<TColor>(this);
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
// ReSharper disable once ForCanBeConvertedToForeach
for (int i = 0; i < this.Frames.Count; i++)
{
this.Frames[i].Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>

145
src/ImageSharp/Image/PixelAccessor{TColor}.cs

@ -44,6 +44,11 @@ namespace ImageSharp
/// </remarks>
private bool isDisposed;
/// <summary>
/// The pixel buffer
/// </summary>
private TColor[] pixelBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class.
/// </summary>
@ -54,40 +59,51 @@ namespace ImageSharp
Guard.MustBeGreaterThan(image.Width, 0, "image width");
Guard.MustBeGreaterThan(image.Height, 0, "image height");
this.Width = image.Width;
this.Height = image.Height;
this.pixelsHandle = GCHandle.Alloc(image.Pixels, GCHandleType.Pinned);
this.dataPointer = this.pixelsHandle.AddrOfPinnedObject();
this.pixelsBase = (byte*)this.dataPointer.ToPointer();
this.PixelSize = Unsafe.SizeOf<TColor>();
this.RowStride = this.Width * this.PixelSize;
this.SetPixelBufferUnsafe(image.Width, image.Height, image.Pixels, false);
this.ParallelOptions = image.Configuration.ParallelOptions;
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class.
/// </summary>
/// <param name="width">Gets the width of the image represented by the pixel buffer.</param>
/// <param name="width">The width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
/// <param name="pixels">The pixel buffer.</param>
public PixelAccessor(int width, int height, TColor[] pixels)
: this(width, height, pixels, false)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class.
/// </summary>
/// <param name="width">The width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
public PixelAccessor(int width, int height)
: this(width, height, PixelPool<TColor>.RentPixels(width * height), true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}" /> class.
/// </summary>
/// <param name="width">The width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
/// <param name="pixels">The pixel buffer.</param>
/// <param name="pooledMemory">if set to <c>true</c> then the <see cref="T:TColor[]"/> is from the <see cref="PixelPool{TColor}"/> thus should be returned once disposed.</param>
private PixelAccessor(int width, int height, TColor[] pixels, bool pooledMemory)
{
Guard.NotNull(pixels, nameof(pixels));
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
if (pixels.Length != width * height)
if (!(pixels.Length >= width * height))
{
throw new ArgumentException("Pixel array must have the length of Width * Height.");
throw new ArgumentException($"Pixel array must have the length of at least {width * height}.");
}
this.Width = width;
this.Height = height;
this.pixelsHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
this.dataPointer = this.pixelsHandle.AddrOfPinnedObject();
this.pixelsBase = (byte*)this.dataPointer.ToPointer();
this.PixelSize = Unsafe.SizeOf<TColor>();
this.RowStride = this.Width * this.PixelSize;
this.SetPixelBufferUnsafe(width, height, pixels, pooledMemory);
this.ParallelOptions = Configuration.Default.ParallelOptions;
}
@ -99,6 +115,11 @@ namespace ImageSharp
this.Dispose();
}
/// <summary>
/// Gets a value indicating whether the current pixel buffer is from a pooled source.
/// </summary>
public bool PooledMemory { get; private set; }
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
@ -107,22 +128,22 @@ namespace ImageSharp
/// <summary>
/// Gets the size of a single pixel in the number of bytes.
/// </summary>
public int PixelSize { get; }
public int PixelSize { get; private set; }
/// <summary>
/// Gets the width of one row in the number of bytes.
/// </summary>
public int RowStride { get; }
public int RowStride { get; private set; }
/// <summary>
/// Gets the width of the image.
/// </summary>
public int Width { get; }
public int Width { get; private set; }
/// <summary>
/// Gets the height of the image.
/// </summary>
public int Height { get; }
public int Height { get; private set; }
/// <summary>
/// Gets the global parallel options for processing tasks in parallel.
@ -221,13 +242,7 @@ namespace ImageSharp
return;
}
if (this.pixelsHandle.IsAllocated)
{
this.pixelsHandle.Free();
}
this.dataPointer = IntPtr.Zero;
this.pixelsBase = null;
this.UnPinPixels();
// Note disposing is done.
this.isDisposed = true;
@ -238,6 +253,12 @@ namespace ImageSharp
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
if (this.PooledMemory)
{
PixelPool<TColor>.ReturnPixels(this.pixelBuffer);
this.pixelBuffer = null;
}
}
/// <summary>
@ -248,6 +269,22 @@ namespace ImageSharp
Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height));
}
/// <summary>
/// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!!
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="pixels">The pixels.</param>
/// <param name="pooledMemory">If set to <c>true</c> this indicates that the pixel buffer is from a pooled source.</param>
/// <returns>Returns the old pixel data thats has gust been replaced.</returns>
/// <remarks>If <see cref="M:PixelAccessor.PooledMemory"/> is true then caller is responsible for ensuring <see cref="M:PixelPool.ReturnPixels()"/> is called.</remarks>
internal TColor[] ReturnCurrentPixelsAndReplaceThemInternally(int width, int height, TColor[] pixels, bool pooledMemory)
{
TColor[] oldPixels = this.pixelBuffer;
this.SetPixelBufferUnsafe(width, height, pixels, pooledMemory);
return oldPixels;
}
/// <summary>
/// Copies the pixels to another <see cref="PixelAccessor{TColor}"/> of the same size.
/// </summary>
@ -472,6 +509,54 @@ namespace ImageSharp
return this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf<TColor>());
}
/// <summary>
/// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!!
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="pixels">The pixels.</param>
/// <param name="pooledMemory">If set to <c>true</c> this indicates that the pixel buffer is from a pooled source.</param>
private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels, bool pooledMemory)
{
this.pixelBuffer = pixels;
this.PooledMemory = pooledMemory;
this.Width = width;
this.Height = height;
this.PinPixels();
this.PixelSize = Unsafe.SizeOf<TColor>();
this.RowStride = this.Width * this.PixelSize;
}
/// <summary>
/// Pins the pixels data.
/// </summary>
private void PinPixels()
{
// unpin any old pixels just incase
this.UnPinPixels();
this.pixelsHandle = GCHandle.Alloc(this.pixelBuffer, GCHandleType.Pinned);
this.dataPointer = this.pixelsHandle.AddrOfPinnedObject();
this.pixelsBase = (byte*)this.dataPointer.ToPointer();
}
/// <summary>
/// Unpins pixels data.
/// </summary>
private void UnPinPixels()
{
if (this.pixelsBase != null)
{
if (this.pixelsHandle.IsAllocated)
{
this.pixelsHandle.Free();
}
this.dataPointer = IntPtr.Zero;
this.pixelsBase = null;
}
}
/// <summary>
/// Copy an area of pixels to the image.
/// </summary>
@ -551,13 +636,13 @@ namespace ImageSharp
int width = Math.Min(area.Width, this.Width - x);
if (width < 1)
{
throw new ArgumentOutOfRangeException(nameof(width), width, $"Invalid area size specified.");
throw new ArgumentOutOfRangeException(nameof(width), width, "Invalid area size specified.");
}
int height = Math.Min(area.Height, this.Height - y);
if (height < 1)
{
throw new ArgumentOutOfRangeException(nameof(height), height, $"Invalid area size specified.");
throw new ArgumentOutOfRangeException(nameof(height), height, "Invalid area size specified.");
}
}

42
src/ImageSharp/Image/PixelPool{TColor}.cs

@ -0,0 +1,42 @@
// <copyright file="PixelPool{TColor}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Buffers;
/// <summary>
/// Provides a resource pool that enables reusing instances of type <see cref="T:TColor[]"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public static class PixelPool<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
/// <summary>
/// The <see cref="ArrayPool{T}"/> used to pool data. TODO: Choose sensible default size and count
/// </summary>
private static readonly ArrayPool<TColor> ArrayPool = ArrayPool<TColor>.Create(int.MaxValue, 50);
/// <summary>
/// Rents the pixel array from the pool.
/// </summary>
/// <param name="minimumLength">The minimum length of the array to return.</param>
/// <returns>The <see cref="T:TColor[]"/></returns>
public static TColor[] RentPixels(int minimumLength)
{
return ArrayPool.Rent(minimumLength);
}
/// <summary>
/// Returns the rented pixel array back to the pool.
/// </summary>
/// <param name="array">The array to return to the buffer pool.</param>
public static void ReturnPixels(TColor[] array)
{
ArrayPool.Return(array, true);
}
}
}

30
src/ImageSharp/Quantizers/Quantize.cs

@ -60,20 +60,26 @@ namespace ImageSharp
int pixelCount = quantized.Pixels.Length;
int palleteCount = quantized.Palette.Length - 1;
TColor[] pixels = new TColor[pixelCount];
Parallel.For(
0,
pixelCount,
source.Configuration.ParallelOptions,
i =>
{
TColor color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])];
pixels[i] = color;
});
using (PixelAccessor<TColor> pixels = new PixelAccessor<TColor>(quantized.Width, quantized.Height))
{
Parallel.For(
0,
pixels.Height,
source.Configuration.ParallelOptions,
y =>
{
for (var x = 0; x < pixels.Width; x++)
{
var i = x + (y * pixels.Width);
TColor color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])];
pixels[x, y] = color;
}
});
source.SetPixels(source.Width, source.Height, pixels);
return source;
source.SwapPixelsBuffers(pixels);
return source;
}
}
}
}

2
src/ImageSharp/project.json

@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha1-*",
"version": "1.0.0-alpha2-*",
"title": "ImageSharp",
"description": "A cross-platform library for the processing of image files; written in C#",
"authors": [

18
tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs

@ -47,18 +47,22 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Beziers")]
public void DrawLinesCore()
{
CoreImage image = new CoreImage(800, 800);
image.DrawBeziers(CoreColor.HotPink, 10, new[] {
using (CoreImage image = new CoreImage(800, 800))
{
image.DrawBeziers(
CoreColor.HotPink,
10,
new[] {
new Vector2(10, 500),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 500)
});
});
using (MemoryStream ms = new MemoryStream())
{
image.SaveAsBmp(ms);
using (MemoryStream ms = new MemoryStream())
{
image.SaveAsBmp(ms);
}
}
}
}

24
tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs

@ -46,17 +46,21 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Lines")]
public void DrawLinesCore()
{
CoreImage image = new CoreImage(800, 800);
image.DrawLines(CoreColor.HotPink, 10, new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
using (MemoryStream ms = new MemoryStream())
using (CoreImage image = new CoreImage(800, 800))
{
image.SaveAsBmp(ms);
image.DrawLines(
CoreColor.HotPink,
10,
new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
using (MemoryStream ms = new MemoryStream())
{
image.SaveAsBmp(ms);
}
}
}
}

24
tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs

@ -45,17 +45,21 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Polygon")]
public void DrawPolygonCore()
{
CoreImage image = new CoreImage(800, 800);
image.DrawPolygon(CoreColor.HotPink, 10, new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
using (MemoryStream ms = new MemoryStream())
using (CoreImage image = new CoreImage(800, 800))
{
image.SaveAsBmp(ms);
image.DrawPolygon(
CoreColor.HotPink,
10,
new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
using (MemoryStream ms = new MemoryStream())
{
image.SaveAsBmp(ms);
}
}
}
}

23
tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs

@ -44,17 +44,20 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill Polygon")]
public void DrawSolidPolygonCore()
{
CoreImage image = new CoreImage(800, 800);
image.FillPolygon(CoreColor.HotPink,
new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
using (MemoryStream ms = new MemoryStream())
using (CoreImage image = new CoreImage(800, 800))
{
image.SaveAsBmp(ms);
image.FillPolygon(
CoreColor.HotPink,
new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
using (MemoryStream ms = new MemoryStream())
{
image.SaveAsBmp(ms);
}
}
}
}

29
tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs

@ -28,7 +28,6 @@ namespace ImageSharp.Benchmarks
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
var pen = new Pen(Color.HotPink, 10);
graphics.FillRectangle(Brushes.HotPink, new Rectangle(10, 10, 190, 140));
}
return destination.Size;
@ -38,25 +37,29 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill Rectangle")]
public CoreSize FillRactangleCore()
{
CoreImage image = new CoreImage(800, 800);
image.Fill(CoreColor.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new CoreRectangle(10, 10, 190, 140)));
using (CoreImage image = new CoreImage(800, 800))
{
image.Fill(CoreColor.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new CoreRectangle(10, 10, 190, 140)));
return new CoreSize(image.Width, image.Height);
return new CoreSize(image.Width, image.Height);
}
}
[Benchmark(Description = "ImageSharp Fill Rectangle - As Polygon")]
public CoreSize FillPolygonCore()
{
CoreImage image = new CoreImage(800, 800);
image.FillPolygon(CoreColor.HotPink, new[] {
new Vector2(10, 10),
new Vector2(200, 10),
new Vector2(200, 150),
new Vector2(10, 150) });
using (CoreImage image = new CoreImage(800, 800))
{
image.FillPolygon(
CoreColor.HotPink,
new[] {
new Vector2(10, 10),
new Vector2(200, 10),
new Vector2(200, 150),
new Vector2(10, 150) });
return new CoreSize(image.Width, image.Height);
return new CoreSize(image.Width, image.Height);
}
}
}
}

12
tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs

@ -38,12 +38,14 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill with Pattern")]
public void DrawPatternPolygon3Core()
{
CoreImage image = new CoreImage(800, 800);
image.Fill(CoreBrushes.BackwardDiagonal(CoreColor.HotPink));
using (MemoryStream ms = new MemoryStream())
using (CoreImage image = new CoreImage(800, 800))
{
image.SaveAsBmp(ms);
image.Fill(CoreBrushes.BackwardDiagonal(CoreColor.HotPink));
using (MemoryStream ms = new MemoryStream())
{
image.SaveAsBmp(ms);
}
}
}
}

34
tests/ImageSharp.Benchmarks/Image/CopyPixels.cs

@ -17,24 +17,26 @@ namespace ImageSharp.Benchmarks.Image
[Benchmark(Description = "Copy by Pixel")]
public CoreColor CopyByPixel()
{
CoreImage source = new CoreImage(1024, 768);
CoreImage target = new CoreImage(1024, 768);
using (PixelAccessor<CoreColor> sourcePixels = source.Lock())
using (PixelAccessor<CoreColor> targetPixels = target.Lock())
using (CoreImage source = new CoreImage(1024, 768))
using (CoreImage target = new CoreImage(1024, 768))
{
Parallel.For(
0,
source.Height,
Configuration.Default.ParallelOptions,
y =>
{
for (int x = 0; x < source.Width; x++)
{
targetPixels[x, y] = sourcePixels[x, y];
}
});
using (PixelAccessor<CoreColor> sourcePixels = source.Lock())
using (PixelAccessor<CoreColor> targetPixels = target.Lock())
{
Parallel.For(
0,
source.Height,
Configuration.Default.ParallelOptions,
y =>
{
for (int x = 0; x < source.Width; x++)
{
targetPixels[x, y] = sourcePixels[x, y];
}
});
return targetPixels[0, 0];
return targetPixels[0, 0];
}
}
}
}

6
tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs

@ -43,8 +43,10 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.bmpBytes))
{
CoreImage image = new CoreImage(memoryStream);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}

17
tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs

@ -29,37 +29,40 @@ namespace ImageSharp.Benchmarks.Image
this.filter4 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter4.png"));
}
private Image LoadPng(MemoryStream stream)
private Size LoadPng(MemoryStream stream)
{
return new Image(stream);
using (Image image = new Image(stream))
{
return new Size(image.Width, image.Height);
}
}
[Benchmark(Baseline = true, Description = "None-filtered PNG file")]
public Image PngFilter0()
public Size PngFilter0()
{
return LoadPng(filter0);
}
[Benchmark(Description = "Sub-filtered PNG file")]
public Image PngFilter1()
public Size PngFilter1()
{
return LoadPng(filter1);
}
[Benchmark(Description = "Up-filtered PNG file")]
public Image PngFilter2()
public Size PngFilter2()
{
return LoadPng(filter2);
}
[Benchmark(Description = "Average-filtered PNG file")]
public Image PngFilter3()
public Size PngFilter3()
{
return LoadPng(filter3);
}
[Benchmark(Description = "Paeth-filtered PNG file")]
public Image PngFilter4()
public Size PngFilter4()
{
return LoadPng(filter4);
}

6
tests/ImageSharp.Benchmarks/Image/DecodeGif.cs

@ -43,8 +43,10 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.gifBytes))
{
CoreImage image = new CoreImage(memoryStream);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}

6
tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs

@ -43,8 +43,10 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes))
{
CoreImage image = new CoreImage(memoryStream);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}

6
tests/ImageSharp.Benchmarks/Image/DecodePng.cs

@ -43,8 +43,10 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.pngBytes))
{
CoreImage image = new CoreImage(memoryStream);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}

8
tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs

@ -31,6 +31,14 @@ namespace ImageSharp.Benchmarks.Image
}
}
[Cleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public void BmpSystemDrawing()
{

4
tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs

@ -18,7 +18,7 @@ namespace ImageSharp.Benchmarks.Image
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
[Benchmark(Description = "EncodeBmpMultiple - ImageSharp")]
public void EncodeGifImageSharp()
public void EncodeBmpImageSharp()
{
this.ForEachImageSharpImage(
(img, ms) =>
@ -29,7 +29,7 @@ namespace ImageSharp.Benchmarks.Image
}
[Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")]
public void EncodeGifSystemDrawing()
public void EncodeBmpSystemDrawing()
{
this.ForEachSystemDrawingImage(
(img, ms) =>

8
tests/ImageSharp.Benchmarks/Image/EncodeGif.cs

@ -31,6 +31,14 @@ namespace ImageSharp.Benchmarks.Image
}
}
[Cleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public void GifSystemDrawing()
{

8
tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs

@ -31,6 +31,14 @@ namespace ImageSharp.Benchmarks.Image
}
}
[Cleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Jpeg")]
public void JpegSystemDrawing()
{

8
tests/ImageSharp.Benchmarks/Image/EncodePng.cs

@ -31,6 +31,14 @@ namespace ImageSharp.Benchmarks.Image
}
}
[Cleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public void PngSystemDrawing()
{

10
tests/ImageSharp.Benchmarks/Image/GetSetPixel.cs

@ -28,11 +28,13 @@ namespace ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp GetSet pixel")]
public CoreColor ResizeCore()
{
CoreImage image = new CoreImage(400, 400);
using (PixelAccessor<CoreColor> imagePixels = image.Lock())
using (CoreImage image = new CoreImage(400, 400))
{
imagePixels[200, 200] = CoreColor.White;
return imagePixels[200, 200];
using (PixelAccessor<CoreColor> imagePixels = image.Lock())
{
imagePixels[200, 200] = CoreColor.White;
return imagePixels[200, 200];
}
}
}
}

8
tests/ImageSharp.Benchmarks/Samplers/Crop.cs

@ -38,9 +38,11 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Crop")]
public CoreSize CropResizeCore()
{
CoreImage image = new CoreImage(800, 800);
image.Crop(100, 100);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(800, 800))
{
image.Crop(100, 100);
return new CoreSize(image.Width, image.Height);
}
}
}
}

6
tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs

@ -28,6 +28,12 @@ namespace ImageSharp.Benchmarks
}
}
[Cleanup]
public void Cleanup()
{
this.image.Dispose();
}
[Benchmark(Description = "ImageSharp DetectEdges")]
public void ImageProcessorCoreDetectEdges()
{

16
tests/ImageSharp.Benchmarks/Samplers/Resize.cs

@ -37,17 +37,21 @@ namespace ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Resize")]
public CoreSize ResizeCore()
{
CoreImage image = new CoreImage(2000, 2000);
image.Resize(400, 400);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(2000, 2000))
{
image.Resize(400, 400);
return new CoreSize(image.Width, image.Height);
}
}
[Benchmark(Description = "ImageSharp Compand Resize")]
public CoreSize ResizeCoreCompand()
{
CoreImage image = new CoreImage(2000, 2000);
image.Resize(400, 400, true);
return new CoreSize(image.Width, image.Height);
using (CoreImage image = new CoreImage(2000, 2000))
{
image.Resize(400, 400, true);
return new CoreSize(image.Width, image.Height);
}
}
}
}

137
tests/ImageSharp.Tests/Drawing/BeziersTests.cs

@ -15,89 +15,88 @@ namespace ImageSharp.Tests.Drawing
public class Beziers : FileTestBase
{
[Fact]
public void ImageShouldBeOverlayedByBezierLine()
{
string path = CreateOutputDirectory("Drawing","BezierLine");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawBeziers(Color.HotPink, 5, new[] {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 400)
})
.Save(output);
}
using (var sourcePixels = image.Lock())
string path = this.CreateOutputDirectory("Drawing", "BezierLine");
using (Image image = new Image(500, 500))
{
//top of curve
Assert.Equal(Color.HotPink, sourcePixels[138,115]);
//start points
Assert.Equal(Color.HotPink, sourcePixels[10, 400]);
Assert.Equal(Color.HotPink, sourcePixels[300, 400]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
// inside shape should be empty
Assert.Equal(Color.Blue, sourcePixels[200, 250]);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image.BackgroundColor(Color.Blue)
.DrawBeziers(Color.HotPink, 5,
new[] {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 400)
})
.Save(output);
}
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(Color.HotPink, sourcePixels[138, 115]);
//start points
Assert.Equal(Color.HotPink, sourcePixels[10, 400]);
Assert.Equal(Color.HotPink, sourcePixels[300, 400]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
// inside shape should be empty
Assert.Equal(Color.Blue, sourcePixels[200, 250]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedBezierLineWithOpacity()
{
string path = CreateOutputDirectory("Drawing", "BezierLine");
string path = this.CreateOutputDirectory("Drawing", "BezierLine");
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawBeziers(color, 10, new[] {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 400)
})
.Save(output);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image.BackgroundColor(Color.Blue)
.DrawBeziers(color,
10,
new[] {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 400)
})
.Save(output);
}
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(mergedColor, sourcePixels[138, 115]);
//start points
Assert.Equal(mergedColor, sourcePixels[10, 400]);
Assert.Equal(mergedColor, sourcePixels[300, 400]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
// inside shape should be empty
Assert.Equal(Color.Blue, sourcePixels[200, 250]);
}
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f/255f));
using (var sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(mergedColor, sourcePixels[138, 115]);
//start points
Assert.Equal(mergedColor, sourcePixels[10, 400]);
Assert.Equal(mergedColor, sourcePixels[300, 400]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
// inside shape should be empty
Assert.Equal(Color.Blue, sourcePixels[200, 250]);
}
}
}
}
}

21
tests/ImageSharp.Tests/Drawing/DrawImageTest.cs

@ -6,7 +6,6 @@
namespace ImageSharp.Tests
{
using System.IO;
using System.Linq;
using Xunit;
@ -15,18 +14,20 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyDrawImageFilter()
{
string path = CreateOutputDirectory("Drawing", "DrawImage");
string path = this.CreateOutputDirectory("Drawing", "DrawImage");
Image blend = TestFile.Create(TestImages.Bmp.Car).CreateImage();
foreach (TestFile file in Files)
using (Image blend = TestFile.Create(TestImages.Bmp.Car).CreateImage())
{
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
foreach (TestFile file in Files)
{
image.DrawImage(blend, 75, new Size(image.Width / 2, image.Height / 2), new Point(image.Width / 4, image.Height / 4))
.Save(output);
using (Image image = file.CreateImage())
{
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.DrawImage(blend, 75, new Size(image.Width / 2, image.Height / 2), new Point(image.Width / 4, image.Height / 4))
.Save(output);
}
}
}
}
}

101
tests/ImageSharp.Tests/Drawing/DrawPathTests.cs

@ -20,81 +20,82 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPath()
{
string path = CreateOutputDirectory("Drawing", "Path");
var image = new Image(500, 500);
var linerSegemnt = new LinearLineSegment(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var bazierSegment = new BezierLineSegment(new Vector2(50, 300),
new Vector2(500, 500),
new Vector2(60, 10),
new Vector2(10, 400));
var p = new CorePath(linerSegemnt, bazierSegment);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPath(Color.HotPink, 5, p)
.Save(output);
}
using (var sourcePixels = image.Lock())
string path = this.CreateOutputDirectory("Drawing", "Path");
using (Image image = new Image(500, 500))
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
LinearLineSegment linerSegemnt = new LinearLineSegment(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
BezierLineSegment bazierSegment = new BezierLineSegment(new Vector2(50, 300),
new Vector2(500, 500),
new Vector2(60, 10),
new Vector2(10, 400));
CorePath p = new CorePath(linerSegemnt, bazierSegment);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPath(Color.HotPink, 5, p)
.Save(output);
}
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedPathWithOpacity()
{
string path = CreateOutputDirectory("Drawing", "Path");
string path = this.CreateOutputDirectory("Drawing", "Path");
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var linerSegemnt = new LinearLineSegment(
LinearLineSegment linerSegemnt = new LinearLineSegment(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
);
var bazierSegment = new BezierLineSegment(new Vector2(50, 300),
BezierLineSegment bazierSegment = new BezierLineSegment(new Vector2(50, 300),
new Vector2(500, 500),
new Vector2(60, 10),
new Vector2(10, 400));
var p = new CorePath(linerSegemnt, bazierSegment);
CorePath p = new CorePath(linerSegemnt, bazierSegment);
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPath(color, 10, p)
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPath(color, 10, p)
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
}
}
}

71
tests/ImageSharp.Tests/Drawing/FillPatternTests.cs

@ -15,55 +15,56 @@ namespace ImageSharp.Tests.Drawing
public class FillPatternBrushTests : FileTestBase
{
private Image Test(string name, Color background, IBrush<Color> brush, Color[,] expectedPattern)
private void Test(string name, Color background, IBrush<Color> brush, Color[,] expectedPattern)
{
string path = CreateOutputDirectory("Fill", "PatternBrush");
Image image = new Image(20, 20);
image
.Fill(background)
.Fill(brush);
using (FileStream output = File.OpenWrite($"{path}/{name}.png"))
{
image.Save(output);
}
using (var sourcePixels = image.Lock())
string path = this.CreateOutputDirectory("Fill", "PatternBrush");
using (Image image = new Image(20, 20))
{
// lets pick random spots to start checking
var r = new Random();
var xStride = expectedPattern.GetLength(1);
var yStride = expectedPattern.GetLength(0);
var offsetX = r.Next(image.Width / xStride) * xStride;
var offsetY = r.Next(image.Height / yStride) * yStride;
for (var x = 0; x < xStride; x++)
image
.Fill(background)
.Fill(brush);
using (FileStream output = File.OpenWrite($"{path}/{name}.png"))
{
for (var y = 0; y < yStride; y++)
image.Save(output);
}
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
// lets pick random spots to start checking
Random r = new Random();
int xStride = expectedPattern.GetLength(1);
int yStride = expectedPattern.GetLength(0);
int offsetX = r.Next(image.Width / xStride) * xStride;
int offsetY = r.Next(image.Height / yStride) * yStride;
for (int x = 0; x < xStride; x++)
{
var actualX = x + offsetX;
var actualY = y + offsetY;
var expected = expectedPattern[y, x]; // inverted pattern
var actual = sourcePixels[actualX, actualY];
if (expected != actual)
for (int y = 0; y < yStride; y++)
{
Assert.True(false, $"Expected {expected} but found {actual} at ({actualX},{actualY})");
int actualX = x + offsetX;
int actualY = y + offsetY;
Color expected = expectedPattern[y, x]; // inverted pattern
Color actual = sourcePixels[actualX, actualY];
if (expected != actual)
{
Assert.True(false, $"Expected {expected} but found {actual} at ({actualX},{actualY})");
}
}
}
}
using (FileStream output = File.OpenWrite($"{path}/{name}x4.png"))
{
image.Resize(80, 80).Save(output);
}
}
using (FileStream output = File.OpenWrite($"{path}/{name}x4.png"))
{
image.Resize(80, 80).Save(output);
}
return image;
}
[Fact]
public void ImageShouldBeFloodFilledWithPercent10()
{
Test("Percent10", Color.Blue, Brushes.Percent10(Color.HotPink, Color.LimeGreen), new Color[,] {
this.Test("Percent10", Color.Blue, Brushes.Percent10(Color.HotPink, Color.LimeGreen),
new[,]
{
{ Color.HotPink , Color.LimeGreen, Color.LimeGreen, Color.LimeGreen},
{ Color.LimeGreen, Color.LimeGreen, Color.LimeGreen, Color.LimeGreen},
{ Color.LimeGreen, Color.LimeGreen, Color.HotPink , Color.LimeGreen},

100
tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs

@ -18,71 +18,73 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeFloodFilledWithColorOnDefaultBackground()
{
string path = CreateOutputDirectory("Fill", "SolidBrush");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/DefaultBack.png"))
string path = this.CreateOutputDirectory("Fill", "SolidBrush");
using (Image image = new Image(500, 500))
{
image
.Fill(Color.HotPink)
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
using (FileStream output = File.OpenWrite($"{path}/DefaultBack.png"))
{
image
.Fill(Color.HotPink)
.Save(output);
}
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
}
}
}
[Fact]
public void ImageShouldBeFloodFilledWithColor()
{
string path = CreateOutputDirectory("Fill", "SolidBrush");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
string path = this.CreateOutputDirectory("Fill", "SolidBrush");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink)
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink)
.Save(output);
}
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
}
}
}
[Fact]
public void ImageShouldBeFloodFilledWithColorOpacity()
{
string path = CreateOutputDirectory("Fill", "SolidBrush");
var image = new Image(500, 500);
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(color)
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
string path = this.CreateOutputDirectory("Fill", "SolidBrush");
using (Image image = new Image(500, 500))
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(color)
.Save(output);
}
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
}
}
}
}

226
tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs

@ -5,12 +5,9 @@
namespace ImageSharp.Tests.Drawing
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Xunit;
using Drawing;
using ImageSharp.Drawing;
using System.Numerics;
using ImageSharp.Drawing.Shapes;
using ImageSharp.Drawing.Pens;
@ -20,98 +17,100 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPolygonOutline()
{
string path = CreateOutputDirectory("Drawing", "LineComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(93, 85),
new Vector2(65, 137));
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[10, 10]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[10, 10]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 300]);
Assert.Equal(Color.HotPink, sourcePixels[50, 300]);
Assert.Equal(Color.HotPink, sourcePixels[37, 85]);
Assert.Equal(Color.HotPink, sourcePixels[37, 85]);
Assert.Equal(Color.HotPink, sourcePixels[93, 85]);
Assert.Equal(Color.HotPink, sourcePixels[93, 85]);
Assert.Equal(Color.HotPink, sourcePixels[65, 137]);
Assert.Equal(Color.HotPink, sourcePixels[65, 137]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByPolygonOutlineNoOverlapping()
{
string path = CreateOutputDirectory("Drawing", "LineComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(207, 25),
new Vector2(263, 25),
new Vector2(235, 57));
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/SimpleVanishHole.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/SimpleVanishHole.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[10, 10]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[10, 10]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 300]);
Assert.Equal(Color.HotPink, sourcePixels[50, 300]);
//Assert.Equal(Color.HotPink, sourcePixels[37, 85]);
//Assert.Equal(Color.HotPink, sourcePixels[37, 85]);
//Assert.Equal(Color.HotPink, sourcePixels[93, 85]);
//Assert.Equal(Color.HotPink, sourcePixels[93, 85]);
//Assert.Equal(Color.HotPink, sourcePixels[65, 137]);
//Assert.Equal(Color.HotPink, sourcePixels[65, 137]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
}
}
}
@ -119,44 +118,45 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPolygonOutlineOverlapping()
{
string path = CreateOutputDirectory("Drawing", "LineComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(130, 40),
new Vector2(65, 137));
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[10, 10]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[10, 10]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 300]);
Assert.Equal(Color.HotPink, sourcePixels[50, 300]);
Assert.Equal(Color.Blue, sourcePixels[130, 41]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[130, 41]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
}
}
}
@ -164,25 +164,26 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPolygonOutlineDashed()
{
string path = CreateOutputDirectory("Drawing", "LineComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(93, 85),
new Vector2(65, 137));
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Dashed.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Pens.Dash(Color.HotPink, 5), new ComplexPolygon(simplePath, hole1))
.Save(output);
using (FileStream output = File.OpenWrite($"{path}/Dashed.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Pens.Dash(Color.HotPink, 5), new ComplexPolygon(simplePath, hole1))
.Save(output);
}
}
}
@ -190,54 +191,55 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedPolygonOutlineWithOpacity()
{
string path = CreateOutputDirectory("Drawing", "LineComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(93, 85),
new Vector2(65, 137));
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(color, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(color, 5, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[10, 10]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[10, 10]);
Assert.Equal(mergedColor, sourcePixels[200, 150]);
Assert.Equal(mergedColor, sourcePixels[200, 150]);
Assert.Equal(mergedColor, sourcePixels[50, 300]);
Assert.Equal(mergedColor, sourcePixels[50, 300]);
Assert.Equal(mergedColor, sourcePixels[37, 85]);
Assert.Equal(mergedColor, sourcePixels[37, 85]);
Assert.Equal(mergedColor, sourcePixels[93, 85]);
Assert.Equal(mergedColor, sourcePixels[93, 85]);
Assert.Equal(mergedColor, sourcePixels[65, 137]);
Assert.Equal(mergedColor, sourcePixels[65, 137]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
//inside shape
Assert.Equal(Color.Blue, sourcePixels[100, 192]);
}
}
}
}

155
tests/ImageSharp.Tests/Drawing/LineTests.cs

@ -5,11 +5,9 @@
namespace ImageSharp.Tests.Drawing
{
using Drawing;
using ImageSharp.Drawing;
using ImageSharp.Drawing.Pens;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Numerics;
using Xunit;
@ -19,123 +17,132 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPath()
{
string path = CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
string path = this.CreateOutputDirectory("Drawing", "Lines");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Color.HotPink, 5, new[] {
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Color.HotPink, 5,
new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
})
.Save(output);
}
})
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByPath_NoAntialias()
{
string path = CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple_noantialias.png"))
string path = this.CreateOutputDirectory("Drawing", "Lines");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Color.HotPink, 5, new[] {
using (FileStream output = File.OpenWrite($"{path}/Simple_noantialias.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Color.HotPink, 5,
new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
}, new GraphicsOptions(false))
.Save(output);
}
},
new GraphicsOptions(false))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByPathDashed()
{
string path = CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Dashed.png"))
string path = this.CreateOutputDirectory("Drawing", "Lines");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Pens.Dash(Color.HotPink, 5), new[] {
using (FileStream output = File.OpenWrite($"{path}/Dashed.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Pens.Dash(Color.HotPink, 5),
new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
})
.Save(output);
})
.Save(output);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByPathDotted()
{
string path = CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Dot.png"))
string path = this.CreateOutputDirectory("Drawing", "Lines");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Pens.Dot(Color.HotPink, 5), new[] {
using (FileStream output = File.OpenWrite($"{path}/Dot.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Pens.Dot(Color.HotPink, 5),
new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
})
.Save(output);
})
.Save(output);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByPathDashDot()
{
string path = CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/DashDot.png"))
string path = this.CreateOutputDirectory("Drawing", "Lines");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Pens.DashDot(Color.HotPink, 5), new[] {
using (FileStream output = File.OpenWrite($"{path}/DashDot.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawLines(Pens.DashDot(Color.HotPink, 5),
new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
})
.Save(output);
})
.Save(output);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByPathDashDotDot()
{
string path = CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
string path = this.CreateOutputDirectory("Drawing", "Lines");
Image image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/DashDotDot.png"))
{
@ -153,12 +160,12 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedPathWithOpacity()
{
string path = CreateOutputDirectory("Drawing", "Lines");
string path = this.CreateOutputDirectory("Drawing", "Lines");
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Image image = new Image(500, 500);
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
@ -173,9 +180,9 @@ namespace ImageSharp.Tests.Drawing
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f/255f));
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f/255f));
using (var sourcePixels = image.Lock())
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
@ -188,9 +195,9 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPathOutline()
{
string path = CreateOutputDirectory("Drawing", "Lines");
string path = this.CreateOutputDirectory("Drawing", "Lines");
var image = new Image(500, 500);
Image image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Rectangle.png"))
{
@ -205,7 +212,7 @@ namespace ImageSharp.Tests.Drawing
.Save(output);
}
using (var sourcePixels = image.Lock())
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[8, 8]);
@ -216,6 +223,6 @@ namespace ImageSharp.Tests.Drawing
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
}
}
}
}

112
tests/ImageSharp.Tests/Drawing/PolygonTests.cs

@ -18,97 +18,101 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPolygonOutline()
{
string path = CreateOutputDirectory("Drawing", "Polygons");
string path = this.CreateOutputDirectory("Drawing", "Polygons");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5, new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
})
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 5,
new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
})
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[9, 9]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.HotPink, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedPolygonOutlineWithOpacity()
{
string path = CreateOutputDirectory("Drawing", "Polygons");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "Polygons");
Vector2[] simplePath = new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(color, 10, simplePath)
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(color, 10, simplePath)
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByRectangleOutline()
{
string path = CreateOutputDirectory("Drawing", "Polygons");
string path = this.CreateOutputDirectory("Drawing", "Polygons");
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Rectangle.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 10, new Rectangle(10, 10, 190, 140))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Rectangle.png"))
{
image
.BackgroundColor(Color.Blue)
.DrawPolygon(Color.HotPink, 10, new Rectangle(10, 10, 190, 140))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[8, 8]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[8, 8]);
Assert.Equal(Color.HotPink, sourcePixels[198, 10]);
Assert.Equal(Color.HotPink, sourcePixels[198, 10]);
Assert.Equal(Color.HotPink, sourcePixels[10, 50]);
Assert.Equal(Color.HotPink, sourcePixels[10, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
}

32
tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs

@ -16,18 +16,19 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldRecolorYellowToHotPink()
{
string path = CreateOutputDirectory("Drawing", "RecolorImage");
string path = this.CreateOutputDirectory("Drawing", "RecolorImage");
var brush = new RecolorBrush(Color.Yellow, Color.HotPink, 0.2f);
RecolorBrush brush = new RecolorBrush(Color.Yellow, Color.HotPink, 0.2f);
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
using (Image image = file.CreateImage())
{
image.Fill(brush)
.Save(output);
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Fill(brush)
.Save(output);
}
}
}
}
@ -35,19 +36,20 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldRecolorYellowToHotPinkInARectangle()
{
string path = CreateOutputDirectory("Drawing", "RecolorImage");
string path = this.CreateOutputDirectory("Drawing", "RecolorImage");
var brush = new RecolorBrush(Color.Yellow, Color.HotPink, 0.2f);
RecolorBrush brush = new RecolorBrush(Color.Yellow, Color.HotPink, 0.2f);
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/Shaped_{file.FileName}"))
using (Image image = file.CreateImage())
{
var imageHeight = image.Height;
image.Fill(brush, new Rectangle(0, imageHeight/2 - imageHeight/4, image.Width, imageHeight/2))
.Save(output);
using (FileStream output = File.OpenWrite($"{path}/Shaped_{file.FileName}"))
{
int imageHeight = image.Height;
image.Fill(brush, new Rectangle(0, imageHeight/2 - imageHeight/4, image.Width, imageHeight/2))
.Save(output);
}
}
}
}

102
tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs

@ -5,11 +5,8 @@
namespace ImageSharp.Tests.Drawing
{
using Drawing;
using ImageSharp.Drawing;
using ImageSharp.Drawing.Shapes;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Numerics;
using Xunit;
@ -19,83 +16,84 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByFilledPolygon()
{
string path = CreateOutputDirectory("Drawing", "FilledBezier");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "FilledBezier");
Vector2[] simplePath = new[] {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 400)
};
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink,new BezierPolygon(simplePath))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink,new BezierPolygon(simplePath))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(Color.HotPink, sourcePixels[138, 116]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(Color.HotPink, sourcePixels[138, 116]);
//start points
Assert.Equal(Color.HotPink, sourcePixels[10, 400]);
Assert.Equal(Color.HotPink, sourcePixels[300, 400]);
//start points
Assert.Equal(Color.HotPink, sourcePixels[10, 400]);
Assert.Equal(Color.HotPink, sourcePixels[300, 400]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
// inside shape should not be empty
Assert.Equal(Color.HotPink, sourcePixels[200, 250]);
// inside shape should not be empty
Assert.Equal(Color.HotPink, sourcePixels[200, 250]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygonOpacity()
{
string path = CreateOutputDirectory("Drawing", "FilledBezier");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "FilledBezier");
Vector2[] simplePath = new[] {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 400)
};
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(color, new BezierPolygon(simplePath))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(color, new BezierPolygon(simplePath))
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(mergedColor, sourcePixels[138, 116]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
//top of curve
Assert.Equal(mergedColor, sourcePixels[138, 116]);
//start points
Assert.Equal(mergedColor, sourcePixels[10, 400]);
Assert.Equal(mergedColor, sourcePixels[300, 400]);
//start points
Assert.Equal(mergedColor, sourcePixels[10, 400]);
Assert.Equal(mergedColor, sourcePixels[300, 400]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
//curve points should not be never be set
Assert.Equal(Color.Blue, sourcePixels[30, 10]);
Assert.Equal(Color.Blue, sourcePixels[240, 30]);
// inside shape should not be empty
Assert.Equal(mergedColor, sourcePixels[200, 250]);
// inside shape should not be empty
Assert.Equal(mergedColor, sourcePixels[200, 250]);
}
}
}
}
}

138
tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs

@ -5,12 +5,9 @@
namespace ImageSharp.Tests.Drawing
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Xunit;
using Drawing;
using ImageSharp.Drawing;
using System.Numerics;
using ImageSharp.Drawing.Shapes;
@ -19,41 +16,42 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByPolygonOutline()
{
string path = CreateOutputDirectory("Drawing", "ComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "ComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(93, 85),
new Vector2(65, 137));
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[35, 100]);
Assert.Equal(Color.HotPink, sourcePixels[35, 100]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
}
}
}
@ -61,87 +59,89 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedPolygonOutlineWithOverlap()
{
string path = CreateOutputDirectory("Drawing", "ComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "ComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(130, 40),
new Vector2(65, 137));
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[35, 100]);
Assert.Equal(Color.HotPink, sourcePixels[35, 100]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedPolygonOutlineWithOpacity()
{
string path = CreateOutputDirectory("Drawing", "ComplexPolygon");
var simplePath = new LinearPolygon(
string path = this.CreateOutputDirectory("Drawing", "ComplexPolygon");
LinearPolygon simplePath = new LinearPolygon(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300));
var hole1 = new LinearPolygon(
LinearPolygon hole1 = new LinearPolygon(
new Vector2(37, 85),
new Vector2(93, 85),
new Vector2(65, 137));
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var image = new Image(500, 500);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(color, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(color, new ComplexPolygon(simplePath, hole1))
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[11, 11]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[11, 11]);
Assert.Equal(mergedColor, sourcePixels[200, 150]);
Assert.Equal(mergedColor, sourcePixels[200, 150]);
Assert.Equal(mergedColor, sourcePixels[50, 50]);
Assert.Equal(mergedColor, sourcePixels[50, 50]);
Assert.Equal(mergedColor, sourcePixels[35, 100]);
Assert.Equal(mergedColor, sourcePixels[35, 100]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
//inside hole
Assert.Equal(Color.Blue, sourcePixels[57, 99]);
}
}
}
}
}
}

156
tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs

@ -5,10 +5,8 @@
namespace ImageSharp.Tests.Drawing
{
using Drawing;
using ImageSharp.Drawing;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Numerics;
using Xunit;
@ -19,155 +17,153 @@ namespace ImageSharp.Tests.Drawing
[Fact]
public void ImageShouldBeOverlayedByFilledPolygon()
{
string path = CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "FilledPolygons");
Vector2[] simplePath = new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.FillPolygon(Color.HotPink, simplePath, new GraphicsOptions(true))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Simple.png"))
{
image
.BackgroundColor(Color.Blue)
.FillPolygon(Color.HotPink, simplePath, new GraphicsOptions(true))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygon_NoAntialias()
public void ImageShouldBeOverlayedByFilledPolygonNoAntialias()
{
string path = CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "FilledPolygons");
Vector2[] simplePath = new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
var image = new Image(500, 500);
using (Image image = new Image(500, 500))
using (FileStream output = File.OpenWrite($"{path}/Simple_NoAntialias.png"))
{
image
.BackgroundColor(Color.Blue)
.FillPolygon(Color.HotPink, simplePath, new GraphicsOptions(false))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[200, 150]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygon_Image()
public void ImageShouldBeOverlayedByFilledPolygonImage()
{
string path = CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "FilledPolygons");
Vector2[] simplePath = new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
var brush = new ImageBrush(TestFile.Create(TestImages.Bmp.Car).CreateImage());
var image = new Image(500, 500);
using (Image brushImage = TestFile.Create(TestImages.Bmp.Car).CreateImage())
using (Image image = new Image(500, 500))
using (FileStream output = File.OpenWrite($"{path}/Image.png"))
{
ImageBrush brush = new ImageBrush(brushImage);
image
.BackgroundColor(Color.Blue)
.FillPolygon(brush, simplePath)
.Save(output);
.BackgroundColor(Color.Blue)
.FillPolygon(brush, simplePath)
.Save(output);
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygonOpacity()
{
string path = CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new[] {
string path = this.CreateOutputDirectory("Drawing", "FilledPolygons");
Vector2[] simplePath = new[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
var color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
var image = new Image(500, 500);
Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150);
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.FillPolygon(color, simplePath)
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Opacity.png"))
{
image
.BackgroundColor(Color.Blue)
.FillPolygon(color, simplePath)
.Save(output);
}
//shift background color towards forground color by the opacity amount
var mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
//shift background color towards forground color by the opacity amount
Color mergedColor = new Color(Vector4.Lerp(Color.Blue.ToVector4(), Color.HotPink.ToVector4(), 150f / 255f));
using (var sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[11, 11]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(mergedColor, sourcePixels[11, 11]);
Assert.Equal(mergedColor, sourcePixels[200, 150]);
Assert.Equal(mergedColor, sourcePixels[200, 150]);
Assert.Equal(mergedColor, sourcePixels[50, 50]);
Assert.Equal(mergedColor, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledRectangle()
{
string path = CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new[] {
new Vector2(10, 10),
new Vector2(200, 10),
new Vector2(200, 150),
new Vector2(10, 150)
};
var image = new Image(500, 500);
using (FileStream output = File.OpenWrite($"{path}/Rectangle.png"))
string path = this.CreateOutputDirectory("Drawing", "FilledPolygons");
using (Image image = new Image(500, 500))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new Rectangle(10,10, 190, 140)))
.Save(output);
}
using (FileStream output = File.OpenWrite($"{path}/Rectangle.png"))
{
image
.BackgroundColor(Color.Blue)
.Fill(Color.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new Rectangle(10, 10, 190, 140)))
.Save(output);
}
using (var sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
using (PixelAccessor<Color> sourcePixels = image.Lock())
{
Assert.Equal(Color.HotPink, sourcePixels[11, 11]);
Assert.Equal(Color.HotPink, sourcePixels[198, 10]);
Assert.Equal(Color.HotPink, sourcePixels[198, 10]);
Assert.Equal(Color.HotPink, sourcePixels[10, 50]);
Assert.Equal(Color.HotPink, sourcePixels[10, 50]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.HotPink, sourcePixels[50, 50]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
Assert.Equal(Color.Blue, sourcePixels[2, 2]);
}
}
}
}

15
tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs

@ -9,8 +9,6 @@ namespace ImageSharp.Tests
{
using System.IO;
using Formats;
using Xunit;
public class BitmapTests : FileTestBase
@ -23,19 +21,20 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("BitsPerPixel")]
[MemberData(nameof(BitsPerPixel))]
public void BitmapCanEncodeDifferentBitRates(BmpBitsPerPixel bitsPerPixel)
{
string path = CreateOutputDirectory("Bmp");
string path = this.CreateOutputDirectory("Bmp");
foreach (TestFile file in Files)
{
string filename = file.GetFileNameWithoutExtension(bitsPerPixel);
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/{filename}.bmp"))
using (Image image = file.CreateImage())
{
image.Save(output, new BmpEncoder { BitsPerPixel = bitsPerPixel });
using (FileStream output = File.OpenWrite($"{path}/{filename}.bmp"))
{
image.Save(output, new BmpEncoder { BitsPerPixel = bitsPerPixel });
}
}
}
}

105
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -16,17 +16,18 @@ namespace ImageSharp.Tests
[Fact]
public void ResolutionShouldChange()
{
string path = CreateOutputDirectory("Resolution");
string path = this.CreateOutputDirectory("Resolution");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
using (Image image = file.CreateImage())
{
image.VerticalResolution = 150;
image.HorizontalResolution = 150;
image.Save(output);
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.VerticalResolution = 150;
image.HorizontalResolution = 150;
image.Save(output);
}
}
}
}
@ -34,45 +35,31 @@ namespace ImageSharp.Tests
[Fact]
public void ImageCanEncodeToString()
{
string path = CreateOutputDirectory("ToString");
string path = this.CreateOutputDirectory("ToString");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
string filename = path + "/" + file.FileNameWithoutExtension + ".txt";
File.WriteAllText(filename, image.ToBase64String());
using (Image image = file.CreateImage())
{
string filename = path + "/" + file.FileNameWithoutExtension + ".txt";
File.WriteAllText(filename, image.ToBase64String());
}
}
}
[Fact]
public void DecodeThenEncodeImageFromStreamShouldSucceed()
{
string path = CreateOutputDirectory("Encode");
string path = this.CreateOutputDirectory("Encode");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
//Image<Bgr565> image = file.CreateImage().To<Bgr565>();
//Image<Bgra4444> image = file.CreateImage().To<Bgra4444>();
//Image<Bgra5551> image = file.CreateImage().To<Bgra5551>();
//Image<Byte4> image = file.CreateImage().To<Byte4>();
//Image<HalfSingle> image = file.CreateImage().To<HalfSingle>();
//Image<HalfVector2> image = file.CreateImage().To<HalfVector2>();
//Image<HalfVector4> image = file.CreateImage().To<HalfVector4>();
//Image<Rg32> image = file.CreateImage().To<Rg32>();
//Image<Rgba1010102> image = file.CreateImage().To<Rgba1010102>();
//Image<Rgba64> image = file.CreateImage().To<Rgba64>();
//Image<NormalizedByte2> image = file.CreateImage().To<NormalizedByte2>();
//Image<NormalizedByte4> image = file.CreateImage().To<NormalizedByte4>();
//Image<NormalizedShort2> image = file.CreateImage().To<NormalizedShort2>();
//Image<NormalizedShort4> image = file.CreateImage().To<NormalizedShort4>();
//Image<Short2> image = file.CreateImage().To<Short2>();
//Image<Short4> image = file.CreateImage().To<Short4>();
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
using (Image image = file.CreateImage())
{
image.Save(output);
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Save(output);
}
}
}
}
@ -80,35 +67,39 @@ namespace ImageSharp.Tests
[Fact]
public void QuantizeImageShouldPreserveMaximumColorPrecision()
{
string path = CreateOutputDirectory("Quantize");
string path = this.CreateOutputDirectory("Quantize");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
// Copy the original pixels to save decoding time.
Color[] pixels = new Color[image.Width * image.Height];
Array.Copy(image.Pixels, pixels, image.Pixels.Length);
using (FileStream output = File.OpenWrite($"{path}/Octree-{file.FileName}"))
using (Image srcImage = file.CreateImage())
{
image.Quantize(Quantization.Octree)
.Save(output, image.CurrentImageFormat);
using (Image image = new Image(srcImage))
{
using (FileStream output = File.OpenWrite($"{path}/Octree-{file.FileName}"))
{
image.Quantize(Quantization.Octree)
.Save(output, image.CurrentImageFormat);
}
}
}
image.SetPixels(image.Width, image.Height, pixels);
using (FileStream output = File.OpenWrite($"{path}/Wu-{file.FileName}"))
{
image.Quantize(Quantization.Wu)
.Save(output, image.CurrentImageFormat);
}
using (Image image = new Image(srcImage))
{
using (FileStream output = File.OpenWrite($"{path}/Wu-{file.FileName}"))
{
image.Quantize(Quantization.Wu)
.Save(output, image.CurrentImageFormat);
}
}
image.SetPixels(image.Width, image.Height, pixels);
using (FileStream output = File.OpenWrite($"{path}/Palette-{file.FileName}"))
{
image.Quantize(Quantization.Palette)
.Save(output, image.CurrentImageFormat);
using (Image image = new Image(srcImage))
{
using (FileStream output = File.OpenWrite($"{path}/Palette-{file.FileName}"))
{
image.Quantize(Quantization.Palette)
.Save(output, image.CurrentImageFormat);
}
}
}
}
}
@ -116,7 +107,7 @@ namespace ImageSharp.Tests
[Fact]
public void ImageCanConvertFormat()
{
string path = CreateOutputDirectory("Format");
string path = this.CreateOutputDirectory("Format");
foreach (TestFile file in Files)
{
@ -147,7 +138,7 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldPreservePixelByteOrderWhenSerialized()
{
string path = CreateOutputDirectory("Serialized");
string path = this.CreateOutputDirectory("Serialized");
foreach (TestFile file in Files)
{

16
tests/ImageSharp.Tests/Formats/Jpg/BadEofJpegTests.cs

@ -31,9 +31,11 @@ namespace ImageSharp.Tests
public void LoadBaselineImage<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
var image = provider.GetImage();
Assert.NotNull(image);
provider.Utility.SaveTestOutputFile(image, "bmp");
using (Image<TColor> image = provider.GetImage())
{
Assert.NotNull(image);
provider.Utility.SaveTestOutputFile(image, "bmp");
}
}
[Theory] // TODO: #18
@ -41,9 +43,11 @@ namespace ImageSharp.Tests
public void LoadProgressiveImage<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
var image = provider.GetImage();
Assert.NotNull(image);
provider.Utility.SaveTestOutputFile(image, "bmp");
using (Image<TColor> image = provider.GetImage())
{
Assert.NotNull(image);
provider.Utility.SaveTestOutputFile(image, "bmp");
}
}
}
}

61
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -29,19 +29,21 @@ namespace ImageSharp.Tests
public void OpenBaselineJpeg_SaveBmp<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = provider.GetImage();
provider.Utility.SaveTestOutputFile(image, "bmp");
using (Image<TColor> image = provider.GetImage())
{
provider.Utility.SaveTestOutputFile(image, "bmp");
}
}
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
public void OpenProgressiveJpeg_SaveBmp<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = provider.GetImage();
provider.Utility.SaveTestOutputFile(image, "bmp");
using (Image<TColor> image = provider.GetImage())
{
provider.Utility.SaveTestOutputFile(image, "bmp");
}
}
[Theory]
@ -53,17 +55,19 @@ namespace ImageSharp.Tests
public void DecodeGenerated_SaveBmp<TColor>(
TestImageProvider<TColor> provider,
JpegSubsample subsample,
int quality)
int quality)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = provider.GetImage();
JpegEncoder encoder = new JpegEncoder() { Subsample = subsample, Quality = quality };
byte[] data = new byte[65536];
using (MemoryStream ms = new MemoryStream(data))
byte[] data;
using (Image<TColor> image = provider.GetImage())
{
image.Save(ms, encoder);
JpegEncoder encoder = new JpegEncoder() { Subsample = subsample, Quality = quality };
data = new byte[65536];
using (MemoryStream ms = new MemoryStream(data))
{
image.Save(ms, encoder);
}
}
// TODO: Automatic image comparers could help here a lot :P
@ -75,23 +79,24 @@ namespace ImageSharp.Tests
[Theory]
[WithSolidFilledImages(42, 88, 255, 0, 0, PixelTypes.StandardImageClass)]
public void DecodeGenerated_MetadataOnly<TColor>(
TestImageProvider<TColor> provider)
TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = provider.GetImage();
using (MemoryStream ms = new MemoryStream())
using (Image<TColor> image = provider.GetImage())
{
image.Save(ms, new JpegEncoder());
ms.Seek(0, SeekOrigin.Begin);
Image<TColor> mirror = provider.Factory.CreateImage(1, 1);
using (JpegDecoderCore decoder = new JpegDecoderCore())
using (MemoryStream ms = new MemoryStream())
{
decoder.Decode(mirror, ms, true);
Assert.Equal(decoder.ImageWidth, image.Width);
Assert.Equal(decoder.ImageHeight, image.Height);
image.Save(ms, new JpegEncoder());
ms.Seek(0, SeekOrigin.Begin);
Image<TColor> mirror = provider.Factory.CreateImage(1, 1);
using (JpegDecoderCore decoder = new JpegDecoderCore())
{
decoder.Decode(mirror, ms, true);
Assert.Equal(decoder.ImageWidth, image.Width);
Assert.Equal(decoder.ImageHeight, image.Height);
}
}
}
}

44
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -34,19 +34,16 @@ namespace ImageSharp.Tests
public void LoadResizeSave<TColor>(TestImageProvider<TColor> provider, int quality, JpegSubsample subsample)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = provider.GetImage()
.Resize(new ResizeOptions
{
Size = new Size(150, 100),
Mode = ResizeMode.Max
});
image.Quality = quality;
image.ExifProfile = null; // Reduce the size of the file
JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality };
using (Image<TColor> image = provider.GetImage().Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))
{
image.Quality = quality;
image.ExifProfile = null; // Reduce the size of the file
JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality };
provider.Utility.TestName += $"{subsample}_Q{quality}";
provider.Utility.SaveTestOutputFile(image, "png");
provider.Utility.SaveTestOutputFile(image, "jpg", encoder);
provider.Utility.TestName += $"{subsample}_Q{quality}";
provider.Utility.SaveTestOutputFile(image, "png");
provider.Utility.SaveTestOutputFile(image, "jpg", encoder);
}
}
[Theory]
@ -55,20 +52,21 @@ namespace ImageSharp.Tests
public void OpenBmp_SaveJpeg<TColor>(TestImageProvider<TColor> provider, JpegSubsample subSample, int quality)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = provider.GetImage();
ImagingTestCaseUtility utility = provider.Utility;
utility.TestName += "_" + subSample + "_Q" + quality;
using (var outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg")))
using (Image<TColor> image = provider.GetImage())
{
var encoder = new JpegEncoder()
ImagingTestCaseUtility utility = provider.Utility;
utility.TestName += "_" + subSample + "_Q" + quality;
using (FileStream outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg")))
{
Subsample = subSample,
Quality = quality
};
JpegEncoder encoder = new JpegEncoder()
{
Subsample = subSample,
Quality = quality
};
image.Save(outputStream, encoder);
image.Save(outputStream, encoder);
}
}
}
}

85
tests/ImageSharp.Tests/Formats/Jpg/JpegUtilsTests.cs

@ -19,7 +19,6 @@ namespace ImageSharp.Tests
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = factory.CreateImage(10, 10);
using (PixelAccessor<TColor> pixels = image.Lock())
{
for (int i = 0; i < 10; i++)
@ -35,6 +34,7 @@ namespace ImageSharp.Tests
}
}
}
return image;
}
@ -43,24 +43,21 @@ namespace ImageSharp.Tests
public void CopyStretchedRGBTo_FromOrigo<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> src = provider.GetImage();
PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz);
Image<TColor> dest = provider.Factory.CreateImage(8, 8);
using (var s = src.Lock())
using (Image<TColor> src = provider.GetImage())
using (Image<TColor> dest = provider.Factory.CreateImage(8, 8))
using (PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz))
using (PixelAccessor<TColor> s = src.Lock())
using (PixelAccessor<TColor> d = dest.Lock())
{
using (var d = dest.Lock())
{
s.CopyRGBBytesStretchedTo(area, 0, 0);
d.CopyFrom(area, 0, 0);
s.CopyRGBBytesStretchedTo(area, 0, 0);
d.CopyFrom(area, 0, 0);
Assert.Equal(s[0, 0], d[0, 0]);
Assert.Equal(s[7, 0], d[7, 0]);
Assert.Equal(s[0, 7], d[0, 7]);
Assert.Equal(s[7, 7], d[7, 7]);
}
Assert.Equal(s[0, 0], d[0, 0]);
Assert.Equal(s[7, 0], d[7, 0]);
Assert.Equal(s[0, 7], d[0, 7]);
Assert.Equal(s[7, 7], d[7, 7]);
}
}
[Theory]
@ -68,45 +65,41 @@ namespace ImageSharp.Tests
public void CopyStretchedRGBTo_WithOffset<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> src = provider.GetImage();
PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz);
Image<TColor> dest = provider.Factory.CreateImage(8, 8);
using (Image<TColor> src = provider.GetImage())
using (PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz))
using (Image<TColor> dest = provider.Factory.CreateImage(8, 8))
using (PixelAccessor<TColor> s = src.Lock())
using (PixelAccessor<TColor> d = dest.Lock())
{
using (var d = dest.Lock())
{
s.CopyRGBBytesStretchedTo(area, 7, 6);
d.CopyFrom(area, 0, 0);
s.CopyRGBBytesStretchedTo(area, 7, 6);
d.CopyFrom(area, 0, 0);
Assert.Equal(s[6, 7], d[0, 0]);
Assert.Equal(s[6, 8], d[0, 1]);
Assert.Equal(s[7, 8], d[1, 1]);
Assert.Equal(s[6, 7], d[0, 0]);
Assert.Equal(s[6, 8], d[0, 1]);
Assert.Equal(s[7, 8], d[1, 1]);
Assert.Equal(s[6, 9], d[0, 2]);
Assert.Equal(s[6, 9], d[0, 3]);
Assert.Equal(s[6, 9], d[0, 7]);
Assert.Equal(s[6, 9], d[0, 2]);
Assert.Equal(s[6, 9], d[0, 3]);
Assert.Equal(s[6, 9], d[0, 7]);
Assert.Equal(s[7, 9], d[1, 2]);
Assert.Equal(s[7, 9], d[1, 3]);
Assert.Equal(s[7, 9], d[1, 7]);
Assert.Equal(s[7, 9], d[1, 2]);
Assert.Equal(s[7, 9], d[1, 3]);
Assert.Equal(s[7, 9], d[1, 7]);
Assert.Equal(s[9, 9], d[3, 2]);
Assert.Equal(s[9, 9], d[3, 3]);
Assert.Equal(s[9, 9], d[3, 7]);
Assert.Equal(s[9, 9], d[3, 2]);
Assert.Equal(s[9, 9], d[3, 3]);
Assert.Equal(s[9, 9], d[3, 7]);
Assert.Equal(s[9, 7], d[3, 0]);
Assert.Equal(s[9, 7], d[4, 0]);
Assert.Equal(s[9, 7], d[7, 0]);
Assert.Equal(s[9, 7], d[3, 0]);
Assert.Equal(s[9, 7], d[4, 0]);
Assert.Equal(s[9, 7], d[7, 0]);
Assert.Equal(s[9, 9], d[3, 2]);
Assert.Equal(s[9, 9], d[4, 2]);
Assert.Equal(s[9, 9], d[7, 2]);
Assert.Equal(s[9, 9], d[3, 2]);
Assert.Equal(s[9, 9], d[4, 2]);
Assert.Equal(s[9, 9], d[7, 2]);
Assert.Equal(s[9, 9], d[4, 3]);
Assert.Equal(s[9, 9], d[7, 7]);
}
Assert.Equal(s[9, 9], d[4, 3]);
Assert.Equal(s[9, 9], d[7, 7]);
}
}
}

4
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs

@ -6,8 +6,6 @@
// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests.Formats.Jpg
{
using System.Numerics;
using ImageSharp.Formats;
using ImageSharp.Formats.Jpg;
using Xunit;
@ -97,7 +95,7 @@ namespace ImageSharp.Tests.Formats.Jpg
Assert.Equal(expected, actual, new ApproximateFloatComparer(2f));
}
}
[Theory]
[InlineData(42)]
[InlineData(1)]

20
tests/ImageSharp.Tests/Formats/Png/PngTests.cs

@ -23,12 +23,13 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png"))
using (Image image = file.CreateImage())
{
image.Quality = 256;
image.Save(output, new PngFormat());
using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png"))
{
image.Quality = 256;
image.Save(output, new PngFormat());
}
}
}
}
@ -42,11 +43,12 @@ namespace ImageSharp.Tests
Files,
file =>
{
Image image = file.CreateImage();
using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png"))
using (Image image = file.CreateImage())
{
image.SaveAsPng(output);
using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png"))
{
image.SaveAsPng(output);
}
}
});
}

9
tests/ImageSharp.Tests/Image/ImageTests.cs

@ -23,10 +23,11 @@ namespace ImageSharp.Tests
});
TestFile file = TestFile.Create(TestImages.Bmp.Car);
Image image = new Image(file.Bytes);
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
using (Image image = new Image(file.Bytes))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
}
}
}
}

118
tests/ImageSharp.Tests/Image/PixelAccessorTests.cs

@ -19,8 +19,7 @@ namespace ImageSharp.Tests
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = factory.CreateImage(10, 10);
using (var pixels = image.Lock())
using (PixelAccessor<TColor> pixels = image.Lock())
{
for (int i = 0; i < 10; i++)
{
@ -47,31 +46,33 @@ namespace ImageSharp.Tests
public void CopyTo_Then_CopyFrom_OnFullImageRect<TColor>(TestImageProvider<TColor> provider, ComponentOrder order)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
var src = provider.GetImage();
var dest = new Image<TColor>(src.Width, src.Height);
using (PixelArea<TColor> area = new PixelArea<TColor>(src.Width, src.Height, order))
using (Image<TColor> src = provider.GetImage())
{
using (var srcPixels = src.Lock())
using (Image<TColor> dest = new Image<TColor>(src.Width, src.Height))
{
srcPixels.CopyTo(area, 0, 0);
}
using (PixelArea<TColor> area = new PixelArea<TColor>(src.Width, src.Height, order))
{
using (PixelAccessor<TColor> srcPixels = src.Lock())
{
srcPixels.CopyTo(area, 0, 0);
}
using (PixelAccessor<TColor> destPixels = dest.Lock())
{
destPixels.CopyFrom(area, 0, 0);
}
}
using (var destPixels = dest.Lock())
{
destPixels.CopyFrom(area, 0, 0);
Assert.True(src.IsEquivalentTo(dest, false));
}
}
Assert.True(src.IsEquivalentTo(dest, false));
}
// TODO: Need a processor in the library with this signature
private static void Fill<TColor>(Image<TColor> image, Rectangle region, TColor color)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
using (var pixels = image.Lock())
using (PixelAccessor<TColor> pixels = image.Lock())
{
for (int y = region.Top; y < region.Bottom; y++)
{
@ -88,87 +89,114 @@ namespace ImageSharp.Tests
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Zyx)]
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Xyzw)]
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Zyxw)]
public void CopyTo_Then_CopyFrom_WithOffset<TColor>(TestImageProvider<TColor> provider, ComponentOrder order)
public void CopyToThenCopyFromWithOffset<TColor>(TestImageProvider<TColor> provider, ComponentOrder order)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
var srcImage = provider.GetImage();
var color = default(TColor);
color.PackFromBytes(255, 0, 0, 255);
Fill(srcImage, new Rectangle(4, 4, 8, 8), color);
var destImage = new Image<TColor>(8, 8);
using (var srcPixels = srcImage.Lock())
using (Image<TColor> destImage = new Image<TColor>(8, 8))
{
using (var area = new PixelArea<TColor>(8, 8, order))
TColor color;
using (Image<TColor> srcImage = provider.GetImage())
{
srcPixels.CopyTo(area, 4, 4);
color = default(TColor);
color.PackFromBytes(255, 0, 0, 255);
using (var destPixels = destImage.Lock())
Fill(srcImage, new Rectangle(4, 4, 8, 8), color);
using (PixelAccessor<TColor> srcPixels = srcImage.Lock())
{
destPixels.CopyFrom(area, 0, 0);
using (PixelArea<TColor> area = new PixelArea<TColor>(8, 8, order))
{
srcPixels.CopyTo(area, 4, 4);
using (PixelAccessor<TColor> destPixels = destImage.Lock())
{
destPixels.CopyFrom(area, 0, 0);
}
}
}
}
}
provider.Utility.SourceFileOrDescription = order.ToString();
provider.Utility.SaveTestOutputFile(destImage, "bmp");
var expectedImage = new Image<TColor>(8, 8).Fill(color);
provider.Utility.SourceFileOrDescription = order.ToString();
provider.Utility.SaveTestOutputFile(destImage, "bmp");
Assert.True(destImage.IsEquivalentTo(expectedImage));
using (Image<TColor> expectedImage = new Image<TColor>(8, 8).Fill(color))
{
Assert.True(destImage.IsEquivalentTo(expectedImage));
}
}
}
[Fact]
public void CopyFromZYX()
{
CopyFromZYX(new Image(1, 1));
using (Image<Color> image = new Image<Color>(1, 1))
{
CopyFromZYX(image);
}
}
[Fact]
public void CopyFromZYXOptimized()
{
CopyFromZYX(new Image(1, 1));
using (Image image = new Image(1, 1))
{
CopyFromZYX(image);
}
}
[Fact]
public void CopyFromZYXW()
{
CopyFromZYXW(new Image(1, 1));
using (Image<Color> image = new Image<Color>(1, 1))
{
CopyFromZYXW(image);
}
}
[Fact]
public void CopyFromZYXWOptimized()
{
CopyFromZYXW(new Image(1, 1));
using (Image image = new Image(1, 1))
{
CopyFromZYXW(image);
}
}
[Fact]
public void CopyToZYX()
{
CopyToZYX(new Image(1, 1));
using (Image<Color> image = new Image<Color>(1, 1))
{
CopyToZYX(image);
}
}
[Fact]
public void CopyToZYXOptimized()
{
CopyToZYX(new Image(1, 1));
using (Image image = new Image(1, 1))
{
CopyToZYX(image);
}
}
[Fact]
public void CopyToZYXW()
{
CopyToZYXW(new Image(1, 1));
using (Image<Color> image = new Image<Color>(1, 1))
{
CopyToZYXW(image);
}
}
[Fact]
public void CopyToZYXWOptimized()
{
CopyToZYXW(new Image(1, 1));
using (Image image = new Image(1, 1))
{
CopyToZYXW(image);
}
}
private static void CopyFromZYX<TColor>(Image<TColor> image)

74
tests/ImageSharp.Tests/Image/PixelPoolTests.cs

@ -0,0 +1,74 @@
// <copyright file="PixelPoolTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System.Linq;
using Xunit;
/// <summary>
/// Tests the <see cref="PixelAccessor"/> class.
/// </summary>
public class PixelPoolTests
{
[Fact]
public void PixelPoolRentsMinimumSize()
{
Color[] pixels = PixelPool<Color>.RentPixels(1024);
Assert.True(pixels.Length >= 1024);
}
[Fact]
public void PixelPoolRentsEmptyArray()
{
for (int i = 16; i < 1024; i += 16)
{
Color[] pixels = PixelPool<Color>.RentPixels(i);
Assert.True(pixels.All(p => p == default(Color)));
PixelPool<Color>.ReturnPixels(pixels);
}
for (int i = 16; i < 1024; i += 16)
{
Color[] pixels = PixelPool<Color>.RentPixels(i);
Assert.True(pixels.All(p => p == default(Color)));
PixelPool<Color>.ReturnPixels(pixels);
}
}
[Fact]
public void PixelPoolDoesNotThrowWhenReturningNonPooled()
{
Color[] pixels = new Color[1024];
PixelPool<Color>.ReturnPixels(pixels);
Assert.True(pixels.Length >= 1024);
}
[Fact]
public void PixelPoolCleansRentedArray()
{
Color[] pixels = PixelPool<Color>.RentPixels(256);
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = Color.Azure;
}
Assert.True(pixels.All(p => p == Color.Azure));
PixelPool<Color>.ReturnPixels(pixels);
Assert.True(pixels.All(p => p == default(Color)));
}
}
}

20
tests/ImageSharp.Tests/Processors/Filters/AlphaTest.cs

@ -19,39 +19,35 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("AlphaValues")]
[MemberData(nameof(AlphaValues))]
public void ImageShouldApplyAlphaFilter(int value)
{
string path = CreateOutputDirectory("Alpha");
string path = this.CreateOutputDirectory("Alpha");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Alpha(value)
.Save(output);
image.Alpha(value).Save(output);
}
}
}
[Theory]
[MemberData("AlphaValues")]
[MemberData(nameof(AlphaValues))]
public void ImageShouldApplyAlphaFilterInBox(int value)
{
string path = CreateOutputDirectory("Alpha");
string path = this.CreateOutputDirectory("Alpha");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Alpha(value, new Rectangle(10, 10, image.Width / 2, image.Height / 2))
.Save(output);
image.Alpha(value, new Rectangle(10, 10, image.Width / 2, image.Height / 2)).Save(output);
}
}
}

19
tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs

@ -26,25 +26,22 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("OrientationValues")]
[MemberData(nameof(OrientationValues))]
public void ImageShouldFlip(RotateType rotateType, FlipType flipType, ushort orientation)
{
string path = CreateOutputDirectory("AutoOrient");
string path = this.CreateOutputDirectory("AutoOrient");
TestFile file = TestFile.Create(TestImages.Bmp.F);
Image image = file.CreateImage();
image.ExifProfile = new ExifProfile();
image.ExifProfile.SetValue(ExifTag.Orientation, orientation);
using (FileStream before = File.OpenWrite($"{path}/before-{file.FileName}"))
using (Image image = file.CreateImage())
{
image.ExifProfile = new ExifProfile();
image.ExifProfile.SetValue(ExifTag.Orientation, orientation);
using (FileStream before = File.OpenWrite($"{path}/before-{file.FileName}"))
using (FileStream after = File.OpenWrite($"{path}/after-{file.FileName}"))
{
image.RotateFlip(rotateType, flipType)
.Save(before)
.AutoOrient()
.Save(after);
image.RotateFlip(rotateType, flipType).Save(before).AutoOrient().Save(after);
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/BackgroundColorTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyBackgroundColorFilter()
{
string path = CreateOutputDirectory("BackgroundColor");
string path = this.CreateOutputDirectory("BackgroundColor");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.BackgroundColor(Color.HotPink)
.Save(output);
image.BackgroundColor(Color.HotPink).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/BinaryThreshold.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("BinaryThresholdValues")]
[MemberData(nameof(BinaryThresholdValues))]
public void ImageShouldApplyBinaryThresholdFilter(float value)
{
string path = CreateOutputDirectory("BinaryThreshold");
string path = this.CreateOutputDirectory("BinaryThreshold");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.BinaryThreshold(value)
.Save(output);
image.BinaryThreshold(value).Save(output);
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/BlackWhiteTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyBlackWhiteFilter()
{
string path = CreateOutputDirectory("BlackWhite");
string path = this.CreateOutputDirectory("BlackWhite");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.BlackWhite()
.Save(output);
image.BlackWhite().Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/BoxBlurTest.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("BoxBlurValues")]
[MemberData(nameof(BoxBlurValues))]
public void ImageShouldApplyBoxBlurFilter(int value)
{
string path = CreateOutputDirectory("BoxBlur");
string path = this.CreateOutputDirectory("BoxBlur");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.BoxBlur(value)
.Save(output);
image.BoxBlur(value).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/BrightnessTest.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("BrightnessValues")]
[MemberData(nameof(BrightnessValues))]
public void ImageShouldApplyBrightnessFilter(int value)
{
string path = CreateOutputDirectory("Brightness");
string path = this.CreateOutputDirectory("Brightness");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Brightness(value)
.Save(output);
image.Brightness(value).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/ColorBlindnessTest.cs

@ -26,20 +26,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("ColorBlindnessFilters")]
[MemberData(nameof(ColorBlindnessFilters))]
public void ImageShouldApplyColorBlindnessFilter(ColorBlindness colorBlindness)
{
string path = CreateOutputDirectory("ColorBlindness");
string path = this.CreateOutputDirectory("ColorBlindness");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(colorBlindness);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.ColorBlindness(colorBlindness)
.Save(output);
image.ColorBlindness(colorBlindness).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/ContrastTest.cs

@ -19,19 +19,17 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("ContrastValues")]
[MemberData(nameof(ContrastValues))]
public void ImageShouldApplyContrastFilter(int value)
{
string path = CreateOutputDirectory("Contrast");
string path = this.CreateOutputDirectory("Contrast");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Contrast(value)
.Save(output);
image.Contrast(value).Save(output);
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/CropTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyCropSampler()
{
string path = CreateOutputDirectory("Crop");
string path = this.CreateOutputDirectory("Crop");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Crop(image.Width / 2, image.Height / 2)
.Save(output);
image.Crop(image.Width / 2, image.Height / 2).Save(output);
}
}
}

15
tests/ImageSharp.Tests/Processors/Filters/DetectEdgesTest.cs

@ -31,32 +31,29 @@ namespace ImageSharp.Tests
[MemberData(nameof(DetectEdgesFilters))]
public void ImageShouldApplyDetectEdgesFilter(EdgeDetection detector)
{
string path = CreateOutputDirectory("DetectEdges");
string path = this.CreateOutputDirectory("DetectEdges");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(detector);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.DetectEdges(detector)
.Save(output);
image.DetectEdges(detector).Save(output);
}
}
}
[Theory]
[MemberData("DetectEdgesFilters")]
[MemberData(nameof(DetectEdgesFilters))]
public void ImageShouldApplyDetectEdgesFilterInBox(EdgeDetection detector)
{
string path = CreateOutputDirectory("DetectEdges");
string path = this.CreateOutputDirectory("DetectEdges");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(detector + "-InBox");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.DetectEdges(detector, new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2))

10
tests/ImageSharp.Tests/Processors/Filters/EntropyCropTest.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("EntropyCropValues")]
[MemberData(nameof(EntropyCropValues))]
public void ImageShouldApplyEntropyCropSampler(float value)
{
string path = CreateOutputDirectory("EntropyCrop");
string path = this.CreateOutputDirectory("EntropyCrop");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.EntropyCrop(value)
.Save(output);
image.EntropyCrop(value).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/FlipTests.cs

@ -20,20 +20,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("FlipValues")]
[MemberData(nameof(FlipValues))]
public void ImageShouldFlip(FlipType flipType)
{
string path = CreateOutputDirectory("Flip");
string path = this.CreateOutputDirectory("Flip");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(flipType);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Flip(flipType)
.Save(output);
image.Flip(flipType).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/GaussianBlurTest.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("GaussianBlurValues")]
[MemberData(nameof(GaussianBlurValues))]
public void ImageShouldApplyGaussianBlurFilter(int value)
{
string path = CreateOutputDirectory("GaussianBlur");
string path = this.CreateOutputDirectory("GaussianBlur");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.GaussianBlur(value)
.Save(output);
image.GaussianBlur(value).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/GaussianSharpenTest.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("GaussianSharpenValues")]
[MemberData(nameof(GaussianSharpenValues))]
public void ImageShouldApplyGaussianSharpenFilter(int value)
{
string path = CreateOutputDirectory("GaussianSharpen");
string path = this.CreateOutputDirectory("GaussianSharpen");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.GaussianSharpen(value)
.Save(output);
image.GaussianSharpen(value).Save(output);
}
}
}

31
tests/ImageSharp.Tests/Processors/Filters/GlowTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyGlowFilter()
{
string path = CreateOutputDirectory("Glow");
string path = this.CreateOutputDirectory("Glow");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Glow()
.Save(output);
image.Glow().Save(output);
}
}
}
@ -31,17 +29,15 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyGlowFilterColor()
{
string path = CreateOutputDirectory("Glow");
string path = this.CreateOutputDirectory("Glow");
foreach (TestFile file in Files)
{
string filename = file.GetFileName("Color");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Glow(Color.HotPink)
.Save(output);
image.Glow(Color.HotPink).Save(output);
}
}
}
@ -49,17 +45,15 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyGlowFilterRadius()
{
string path = CreateOutputDirectory("Glow");
string path = this.CreateOutputDirectory("Glow");
foreach (TestFile file in Files)
{
string filename = file.GetFileName("Radius");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Glow(image.Width / 4)
.Save(output);
image.Glow(image.Width / 4F).Save(output);
}
}
}
@ -67,17 +61,16 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyGlowFilterInBox()
{
string path = CreateOutputDirectory("Glow");
string path = this.CreateOutputDirectory("Glow");
foreach (TestFile file in Files)
{
string filename = file.GetFileName("InBox");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Glow(new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2))
.Save(output);
.Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/GrayscaleTest.cs

@ -20,20 +20,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("GrayscaleValues")]
[MemberData(nameof(GrayscaleValues))]
public void ImageShouldApplyGrayscaleFilter(GrayscaleMode value)
{
string path = CreateOutputDirectory("Grayscale");
string path = this.CreateOutputDirectory("Grayscale");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Grayscale(value)
.Save(output);
image.Grayscale(value).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/HueTest.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("HueValues")]
[MemberData(nameof(HueValues))]
public void ImageShouldApplyHueFilter(int value)
{
string path = CreateOutputDirectory("Hue");
string path = this.CreateOutputDirectory("Hue");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Hue(value)
.Save(output);
image.Hue(value).Save(output);
}
}
}

16
tests/ImageSharp.Tests/Processors/Filters/InvertTest.cs

@ -14,15 +14,13 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyInvertFilter()
{
string path = CreateOutputDirectory("Invert");
string path = this.CreateOutputDirectory("Invert");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Invert()
.Save(output);
image.Invert().Save(output);
}
}
}
@ -30,17 +28,15 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyInvertFilterInBox()
{
string path = CreateOutputDirectory("Invert");
string path = this.CreateOutputDirectory("Invert");
foreach (TestFile file in Files)
{
string filename = file.GetFileName("InBox");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Invert(new Rectangle(10, 10, image.Width / 2, image.Height / 2))
.Save(output);
image.Invert(new Rectangle(10, 10, image.Width / 2, image.Height / 2)).Save(output);
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/KodachromeTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyKodachromeFilter()
{
string path = CreateOutputDirectory("Kodachrome");
string path = this.CreateOutputDirectory("Kodachrome");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Kodachrome()
.Save(output);
image.Kodachrome().Save(output);
}
}
}

15
tests/ImageSharp.Tests/Processors/Filters/LomographTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyLomographFilter()
{
string path = CreateOutputDirectory("Lomograph");
string path = this.CreateOutputDirectory("Lomograph");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Lomograph()
.Save(output);
image.Lomograph().Save(output);
}
}
}
@ -31,17 +29,16 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyLomographFilterInBox()
{
string path = CreateOutputDirectory("Lomograph");
string path = this.CreateOutputDirectory("Lomograph");
foreach (TestFile file in Files)
{
string filename = file.GetFileName("InBox");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Lomograph(new Rectangle(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2))
.Save(output);
.Save(output);
}
}
}

21
tests/ImageSharp.Tests/Processors/Filters/OilPaintTest.cs

@ -23,19 +23,17 @@ namespace ImageSharp.Tests
[MemberData(nameof(OilPaintValues))]
public void ImageShouldApplyOilPaintFilter(Tuple<int, int> value)
{
string path = CreateOutputDirectory("OilPaint");
string path = this.CreateOutputDirectory("OilPaint");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
if (image.Width > value.Item2 && image.Height > value.Item2)
{
image.OilPaint(value.Item1, value.Item2)
.Save(output);
image.OilPaint(value.Item1, value.Item2).Save(output);
}
}
}
@ -45,18 +43,19 @@ namespace ImageSharp.Tests
[MemberData(nameof(OilPaintValues))]
public void ImageShouldApplyOilPaintFilterInBox(Tuple<int, int> value)
{
string path = CreateOutputDirectory("OilPaint");
string path = this.CreateOutputDirectory("OilPaint");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value + "-InBox");
Image image = file.CreateImage();
if (image.Width > value.Item2 && image.Height > value.Item2)
using (Image image = file.CreateImage())
{
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
if (image.Width > value.Item2 && image.Height > value.Item2)
{
image.OilPaint(value.Item1, value.Item2, new Rectangle(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2)).Save(output);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.OilPaint(value.Item1, value.Item2, new Rectangle(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2)).Save(output);
}
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/PadTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyPadSampler()
{
string path = CreateOutputDirectory("Pad");
string path = this.CreateOutputDirectory("Pad");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Pad(image.Width + 50, image.Height + 50)
.Save(output);
image.Pad(image.Width + 50, image.Height + 50).Save(output);
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/PixelateTest.cs

@ -41,17 +41,15 @@ namespace ImageSharp.Tests
[MemberData(nameof(PixelateValues))]
public void ImageShouldApplyPixelateFilterInBox(int value)
{
string path = CreateOutputDirectory("Pixelate");
string path = this.CreateOutputDirectory("Pixelate");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(value + "-InBox");
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Pixelate(value, new Rectangle(10, 10, image.Width / 2, image.Height / 2))
.Save(output);
image.Pixelate(value, new Rectangle(10, 10, image.Width / 2, image.Height / 2)).Save(output);
}
}
}

8
tests/ImageSharp.Tests/Processors/Filters/PolaroidTest.cs

@ -14,16 +14,14 @@ namespace ImageSharp.Tests
[Fact]
public void ImageShouldApplyPolaroidFilter()
{
string path = CreateOutputDirectory("Polaroid");
string path = this.CreateOutputDirectory("Polaroid");
foreach (TestFile file in Files)
{
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image.Polaroid()
.Save(output);
image.Polaroid().Save(output);
}
}
}

76
tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs

@ -42,12 +42,10 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Resize(image.Width / 2, image.Height / 2, sampler, true)
.Save(output);
image.Resize(image.Width / 2, image.Height / 2, sampler, true).Save(output);
}
}
}
@ -63,12 +61,10 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Resize(image.Width / 3, 0, sampler, false)
.Save(output);
image.Resize(image.Width / 3, 0, sampler, false).Save(output);
}
}
}
@ -84,12 +80,10 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Resize(0, image.Height / 3, sampler, false)
.Save(output);
image.Resize(0, image.Height / 3, sampler, false).Save(output);
}
}
}
@ -105,18 +99,16 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Sampler = sampler,
Size = new Size(image.Width / 2, image.Height)
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}
@ -132,18 +124,16 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Sampler = sampler,
Size = new Size(image.Width, image.Height / 2)
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}
@ -159,18 +149,16 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Size = new Size(image.Width + 200, image.Height),
Mode = ResizeMode.Pad
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}
@ -186,19 +174,17 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Sampler = sampler,
Size = new Size(image.Width + 200, image.Height + 200),
Mode = ResizeMode.BoxPad
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}
@ -214,19 +200,17 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Sampler = sampler,
Size = new Size(300, 300),
Mode = ResizeMode.Max
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}
@ -242,19 +226,17 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Sampler = sampler,
Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * 95F)),
Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * .95F)),
Mode = ResizeMode.Min
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}
@ -270,19 +252,17 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files)
{
string filename = file.GetFileName(name);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
ResizeOptions options = new ResizeOptions
{
Sampler = sampler,
Size = new Size(image.Width / 2, image.Height),
Mode = ResizeMode.Stretch
};
image.Resize(options)
.Save(output);
image.Resize(options).Save(output);
}
}
}

10
tests/ImageSharp.Tests/Processors/Filters/RotateFlipTest.cs

@ -22,20 +22,18 @@ namespace ImageSharp.Tests
};
[Theory]
[MemberData("RotateFlipValues")]
[MemberData(nameof(RotateFlipValues))]
public void ImageShouldRotateFlip(RotateType rotateType, FlipType flipType)
{
string path = CreateOutputDirectory("RotateFlip");
string path = this.CreateOutputDirectory("RotateFlip");
foreach (TestFile file in Files)
{
string filename = file.GetFileName(rotateType + "-" + flipType);
Image image = file.CreateImage();
using (Image image = file.CreateImage())
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.RotateFlip(rotateType, flipType)
.Save(output);
image.RotateFlip(rotateType, flipType).Save(output);
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save