Browse Source

Merge remote-tracking branch 'origin/master' into webp

# Conflicts:
#	tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
pull/1552/head
Brian Popow 5 years ago
parent
commit
657df2df69
  1. 2
      shared-infrastructure
  2. 19
      tests/ImageSharp.Benchmarks/BenchmarkBase.cs
  3. 29
      tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs
  4. 48
      tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs
  5. 29
      tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs
  6. 29
      tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs
  7. 34
      tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs
  8. 4
      tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs
  9. 23
      tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs
  10. 10
      tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs
  11. 19
      tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs
  12. 10
      tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs
  13. 59
      tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs
  14. 19
      tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs
  15. 11
      tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
  16. 4
      tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs
  17. 32
      tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs
  18. 16
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs
  19. 20
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs
  20. 7
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
  21. 16
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs
  22. 20
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
  23. 32
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
  24. 10
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs
  25. 10
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs
  26. 13
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs
  27. 64
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs
  28. 32
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs
  29. 14
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs
  30. 19
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
  31. 14
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs
  32. 112
      tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
  33. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4_Rgb24.cs
  34. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs
  35. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgb24.cs
  36. 8
      tests/ImageSharp.Benchmarks/Config.cs
  37. 2
      tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs
  38. 2
      tests/ImageSharp.Benchmarks/General/CopyBuffers.cs
  39. 2
      tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs
  40. 28
      tests/ImageSharp.Benchmarks/General/GetSetPixel.cs
  41. 2
      tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
  42. 2
      tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs
  43. 2
      tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs
  44. 2
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  45. 86
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  46. 8
      tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs
  47. 40
      tests/ImageSharp.Benchmarks/Processing/Crop.cs
  48. 20
      tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs
  49. 20
      tests/ImageSharp.Benchmarks/Processing/Diffuse.cs
  50. 6
      tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs
  51. 31
      tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs
  52. 36
      tests/ImageSharp.Benchmarks/Processing/Resize.cs
  53. 12
      tests/ImageSharp.Benchmarks/Processing/Rotate.cs
  54. 12
      tests/ImageSharp.Benchmarks/Processing/Skew.cs
  55. 45
      tests/ImageSharp.Benchmarks/Samplers/Crop.cs

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 3ad6e96a5f900fecd134f0dbba937cb97c7fb94f Subproject commit b7b9a2755e456a96acbf103494228226d92eddf3

19
tests/ImageSharp.Benchmarks/BenchmarkBase.cs

@ -1,19 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Benchmarks
{
/// <summary>
/// The image benchmark base class.
/// </summary>
public abstract class BenchmarkBase
{
/// <summary>
/// Initializes a new instance of the <see cref="BenchmarkBase"/> class.
/// </summary>
protected BenchmarkBase()
{
// Add Image Formats
}
}
}

29
tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs

@ -10,12 +10,13 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeBmp : BenchmarkBase public class DecodeBmp
{ {
private byte[] bmpBytes; private byte[] bmpBytes;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[GlobalSetup] [GlobalSetup]
public void ReadImages() public void ReadImages()
@ -32,25 +33,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")] [Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public SDSize BmpSystemDrawing() public SDSize BmpSystemDrawing()
{ {
using (var memoryStream = new MemoryStream(this.bmpBytes)) using var memoryStream = new MemoryStream(this.bmpBytes);
{ using var image = SDImage.FromStream(memoryStream);
using (var image = SDImage.FromStream(memoryStream)) return image.Size;
{
return image.Size;
}
}
} }
[Benchmark(Description = "ImageSharp Bmp")] [Benchmark(Description = "ImageSharp Bmp")]
public Size BmpCore() public Size BmpImageSharp()
{ {
using (var memoryStream = new MemoryStream(this.bmpBytes)) using var memoryStream = new MemoryStream(this.bmpBytes);
{ using var image = Image.Load<Rgba32>(memoryStream);
using (var image = Image.Load<Rgba32>(memoryStream)) return new Size(image.Width, image.Height);
{
return new Size(image.Width, image.Height);
}
}
} }
} }
} }

48
tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs

@ -6,12 +6,11 @@ using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
using CoreSize = SixLabors.ImageSharp.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeFilteredPng : BenchmarkBase public class DecodeFilteredPng
{ {
private byte[] filter0; private byte[] filter0;
private byte[] filter1; private byte[] filter1;
@ -30,44 +29,33 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
} }
[Benchmark(Baseline = true, Description = "None-filtered PNG file")] [Benchmark(Baseline = true, Description = "None-filtered PNG file")]
public CoreSize PngFilter0() public Size PngFilter0()
{ => LoadPng(this.filter0);
return LoadPng(this.filter0);
}
[Benchmark(Description = "Sub-filtered PNG file")] [Benchmark(Description = "Sub-filtered PNG file")]
public CoreSize PngFilter1() public Size PngFilter1()
{ => LoadPng(this.filter1);
return LoadPng(this.filter1);
}
[Benchmark(Description = "Up-filtered PNG file")] [Benchmark(Description = "Up-filtered PNG file")]
public CoreSize PngFilter2() public Size PngFilter2()
{ => LoadPng(this.filter2);
return LoadPng(this.filter2);
}
[Benchmark(Description = "Average-filtered PNG file")] [Benchmark(Description = "Average-filtered PNG file")]
public CoreSize PngFilter3() public Size PngFilter3()
{ => LoadPng(this.filter3);
return LoadPng(this.filter3);
}
[Benchmark(Description = "Paeth-filtered PNG file")] [Benchmark(Description = "Paeth-filtered PNG file")]
public CoreSize PngFilter4() public Size PngFilter4()
{ => LoadPng(this.filter4);
return LoadPng(this.filter4);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static CoreSize LoadPng(byte[] bytes) private static Size LoadPng(byte[] bytes)
{ {
using (var image = Image.Load<Rgba32>(bytes)) using var image = Image.Load<Rgba32>(bytes);
{ return image.Size();
return image.Size();
}
} }
private static string TestImageFullPath(string path) => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path); private static string TestImageFullPath(string path)
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path);
} }
} }

29
tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs

@ -10,12 +10,13 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeGif : BenchmarkBase public class DecodeGif
{ {
private byte[] gifBytes; private byte[] gifBytes;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[GlobalSetup] [GlobalSetup]
public void ReadImages() public void ReadImages()
@ -32,25 +33,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Baseline = true, Description = "System.Drawing Gif")] [Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public SDSize GifSystemDrawing() public SDSize GifSystemDrawing()
{ {
using (var memoryStream = new MemoryStream(this.gifBytes)) using var memoryStream = new MemoryStream(this.gifBytes);
{ using var image = SDImage.FromStream(memoryStream);
using (var image = SDImage.FromStream(memoryStream)) return image.Size;
{
return image.Size;
}
}
} }
[Benchmark(Description = "ImageSharp Gif")] [Benchmark(Description = "ImageSharp Gif")]
public Size GifCore() public Size GifImageSharp()
{ {
using (var memoryStream = new MemoryStream(this.gifBytes)) using var memoryStream = new MemoryStream(this.gifBytes);
{ using var image = Image.Load<Rgba32>(memoryStream);
using (var image = Image.Load<Rgba32>(memoryStream)) return new Size(image.Width, image.Height);
{
return new Size(image.Width, image.Height);
}
}
} }
} }
} }

29
tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs

@ -10,12 +10,13 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodePng : BenchmarkBase public class DecodePng
{ {
private byte[] pngBytes; private byte[] pngBytes;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[Params(TestImages.Png.Splash)] [Params(TestImages.Png.Splash)]
public string TestImage { get; set; } public string TestImage { get; set; }
@ -32,25 +33,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Baseline = true, Description = "System.Drawing Png")] [Benchmark(Baseline = true, Description = "System.Drawing Png")]
public SDSize PngSystemDrawing() public SDSize PngSystemDrawing()
{ {
using (var memoryStream = new MemoryStream(this.pngBytes)) using var memoryStream = new MemoryStream(this.pngBytes);
{ using var image = SDImage.FromStream(memoryStream);
using (var image = SDImage.FromStream(memoryStream)) return image.Size;
{
return image.Size;
}
}
} }
[Benchmark(Description = "ImageSharp Png")] [Benchmark(Description = "ImageSharp Png")]
public Size PngCore() public Size PngImageSharp()
{ {
using (var memoryStream = new MemoryStream(this.pngBytes)) using var memoryStream = new MemoryStream(this.pngBytes);
{ using var image = Image.Load<Rgba32>(memoryStream);
using (var image = Image.Load<Rgba32>(memoryStream)) return image.Size();
{
return image.Size();
}
}
} }
} }
} }

34
tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs

@ -5,7 +5,6 @@ using System.Buffers;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using ImageMagick; using ImageMagick;
using Pfim; using Pfim;
using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Formats.Tga;
@ -14,8 +13,8 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeTga : BenchmarkBase public class DecodeTga
{ {
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
@ -28,36 +27,28 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[GlobalSetup] [GlobalSetup]
public void SetupData() public void SetupData()
{ => this.data = File.ReadAllBytes(this.TestImageFullPath);
this.data = File.ReadAllBytes(this.TestImageFullPath);
}
[Benchmark(Baseline = true, Description = "ImageMagick Tga")] [Benchmark(Baseline = true, Description = "ImageMagick Tga")]
public int TgaImageMagick() public int TgaImageMagick()
{ {
var settings = new MagickReadSettings { Format = MagickFormat.Tga }; var settings = new MagickReadSettings { Format = MagickFormat.Tga };
using (var image = new MagickImage(new MemoryStream(this.data), settings)) using var image = new MagickImage(new MemoryStream(this.data), settings);
{ return image.Width;
return image.Width;
}
} }
[Benchmark(Description = "ImageSharp Tga")] [Benchmark(Description = "ImageSharp Tga")]
public int TgaCore() public int TgaImageSharp()
{ {
using (var image = Image.Load<Bgr24>(this.data, new TgaDecoder())) using var image = Image.Load<Bgr24>(this.data, new TgaDecoder());
{ return image.Width;
return image.Width;
}
} }
[Benchmark(Description = "Pfim Tga")] [Benchmark(Description = "Pfim Tga")]
public int TgaPfim() public int TgaPfim()
{ {
using (var image = Targa.Create(this.data, this.pfimConfig)) using var image = Targa.Create(this.data, this.pfimConfig);
{ return image.Width;
return image.Width;
}
} }
private class PfimAllocator : IImageAllocator private class PfimAllocator : IImageAllocator
@ -65,10 +56,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
private int rented; private int rented;
private readonly ArrayPool<byte> shared = ArrayPool<byte>.Shared; private readonly ArrayPool<byte> shared = ArrayPool<byte>.Shared;
public byte[] Rent(int size) public byte[] Rent(int size) => this.shared.Rent(size);
{
return this.shared.Rent(size);
}
public void Return(byte[] data) public void Return(byte[] data)
{ {

4
tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs

@ -11,8 +11,8 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeWebp : BenchmarkBase public class DecodeWebp
{ {
private Configuration configuration; private Configuration configuration;

23
tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Drawing.Imaging; using System.Drawing.Imaging;
@ -10,8 +10,8 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeBmp : BenchmarkBase public class EncodeBmp
{ {
private Stream bmpStream; private Stream bmpStream;
private SDImage bmpDrawing; private SDImage bmpDrawing;
@ -33,6 +33,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public void Cleanup() public void Cleanup()
{ {
this.bmpStream.Dispose(); this.bmpStream.Dispose();
this.bmpStream = null;
this.bmpCore.Dispose(); this.bmpCore.Dispose();
this.bmpDrawing.Dispose(); this.bmpDrawing.Dispose();
} }
@ -40,19 +41,15 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")] [Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public void BmpSystemDrawing() public void BmpSystemDrawing()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ this.bmpDrawing.Save(memoryStream, ImageFormat.Bmp);
this.bmpDrawing.Save(memoryStream, ImageFormat.Bmp);
}
} }
[Benchmark(Description = "ImageSharp Bmp")] [Benchmark(Description = "ImageSharp Bmp")]
public void BmpCore() public void BmpImageSharp()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ this.bmpCore.SaveAsBmp(memoryStream);
this.bmpCore.SaveAsBmp(memoryStream);
}
} }
} }
} }

10
tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs

@ -8,29 +8,25 @@ using SixLabors.ImageSharp.Formats.Bmp;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
[Benchmark(Description = "EncodeBmpMultiple - ImageSharp")] [Benchmark(Description = "EncodeBmpMultiple - ImageSharp")]
public void EncodeBmpImageSharp() public void EncodeBmpImageSharp()
{ => this.ForEachImageSharpImage((img, ms) =>
this.ForEachImageSharpImage((img, ms) =>
{ {
img.Save(ms, new BmpEncoder()); img.Save(ms, new BmpEncoder());
return null; return null;
}); });
}
[Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")] [Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")]
public void EncodeBmpSystemDrawing() public void EncodeBmpSystemDrawing()
{ => this.ForEachSystemDrawingImage((img, ms) =>
this.ForEachSystemDrawingImage((img, ms) =>
{ {
img.Save(ms, ImageFormat.Bmp); img.Save(ms, ImageFormat.Bmp);
return null; return null;
}); });
}
} }
} }

19
tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs

@ -13,8 +13,8 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeGif : BenchmarkBase public class EncodeGif
{ {
// System.Drawing needs this. // System.Drawing needs this.
private Stream bmpStream; private Stream bmpStream;
@ -46,6 +46,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public void Cleanup() public void Cleanup()
{ {
this.bmpStream.Dispose(); this.bmpStream.Dispose();
this.bmpStream = null;
this.bmpCore.Dispose(); this.bmpCore.Dispose();
this.bmpDrawing.Dispose(); this.bmpDrawing.Dispose();
} }
@ -53,19 +54,15 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Baseline = true, Description = "System.Drawing Gif")] [Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public void GifSystemDrawing() public void GifSystemDrawing()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ this.bmpDrawing.Save(memoryStream, ImageFormat.Gif);
this.bmpDrawing.Save(memoryStream, ImageFormat.Gif);
}
} }
[Benchmark(Description = "ImageSharp Gif")] [Benchmark(Description = "ImageSharp Gif")]
public void GifCore() public void GifImageSharp()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ this.bmpCore.SaveAsGif(memoryStream, this.encoder);
this.bmpCore.SaveAsGif(memoryStream, this.encoder);
}
} }
} }
} }

10
tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs

@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Processing.Processors.Quantization;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
[Params(InputImageCategory.AllImages)] [Params(InputImageCategory.AllImages)]
@ -20,8 +20,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Description = "EncodeGifMultiple - ImageSharp")] [Benchmark(Description = "EncodeGifMultiple - ImageSharp")]
public void EncodeGifImageSharp() public void EncodeGifImageSharp()
{ => this.ForEachImageSharpImage((img, ms) =>
this.ForEachImageSharpImage((img, ms) =>
{ {
// Try to get as close to System.Drawing's output as possible // Try to get as close to System.Drawing's output as possible
var options = new GifEncoder var options = new GifEncoder
@ -32,16 +31,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
img.Save(ms, options); img.Save(ms, options);
return null; return null;
}); });
}
[Benchmark(Baseline = true, Description = "EncodeGifMultiple - System.Drawing")] [Benchmark(Baseline = true, Description = "EncodeGifMultiple - System.Drawing")]
public void EncodeGifSystemDrawing() public void EncodeGifSystemDrawing()
{ => this.ForEachSystemDrawingImage((img, ms) =>
this.ForEachSystemDrawingImage((img, ms) =>
{ {
img.Save(ms, ImageFormat.Gif); img.Save(ms, ImageFormat.Gif);
return null; return null;
}); });
}
} }
} }

59
tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs

@ -8,15 +8,15 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
using CoreImage = SixLabors.ImageSharp.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
/// <summary> /// <summary>
/// Benchmarks saving png files using different quantizers. System.Drawing cannot save indexed png files so we cannot compare. /// Benchmarks saving png files using different quantizers.
/// System.Drawing cannot save indexed png files so we cannot compare.
/// </summary> /// </summary>
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeIndexedPng : BenchmarkBase public class EncodeIndexedPng
{ {
// System.Drawing needs this. // System.Drawing needs this.
private Stream bmpStream; private Stream bmpStream;
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
if (this.bmpStream == null) if (this.bmpStream == null)
{ {
this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car)); this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car));
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream); this.bmpCore = Image.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0; this.bmpStream.Position = 0;
} }
} }
@ -37,67 +37,56 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public void Cleanup() public void Cleanup()
{ {
this.bmpStream.Dispose(); this.bmpStream.Dispose();
this.bmpStream = null;
this.bmpCore.Dispose(); this.bmpCore.Dispose();
} }
[Benchmark(Baseline = true, Description = "ImageSharp Octree Png")] [Benchmark(Baseline = true, Description = "ImageSharp Octree Png")]
public void PngCoreOctree() public void PngCoreOctree()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var options = new PngEncoder { Quantizer = KnownQuantizers.Octree };
var options = new PngEncoder { Quantizer = KnownQuantizers.Octree }; this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, options);
}
} }
[Benchmark(Description = "ImageSharp Octree NoDither Png")] [Benchmark(Description = "ImageSharp Octree NoDither Png")]
public void PngCoreOctreeNoDither() public void PngCoreOctreeNoDither()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var options = new PngEncoder { Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) };
var options = new PngEncoder { Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) }; this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, options);
}
} }
[Benchmark(Description = "ImageSharp Palette Png")] [Benchmark(Description = "ImageSharp Palette Png")]
public void PngCorePalette() public void PngCorePalette()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe };
var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe }; this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, options);
}
} }
[Benchmark(Description = "ImageSharp Palette NoDither Png")] [Benchmark(Description = "ImageSharp Palette NoDither Png")]
public void PngCorePaletteNoDither() public void PngCorePaletteNoDither()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = null }) };
var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = null }) }; this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, options);
}
} }
[Benchmark(Description = "ImageSharp Wu Png")] [Benchmark(Description = "ImageSharp Wu Png")]
public void PngCoreWu() public void PngCoreWu()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var options = new PngEncoder { Quantizer = KnownQuantizers.Wu };
var options = new PngEncoder { Quantizer = KnownQuantizers.Wu }; this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, options);
}
} }
[Benchmark(Description = "ImageSharp Wu NoDither Png")] [Benchmark(Description = "ImageSharp Wu NoDither Png")]
public void PngCoreWuNoDither() public void PngCoreWuNoDither()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var options = new PngEncoder { Quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }) };
var options = new PngEncoder { Quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }) }; this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, options);
}
} }
} }
} }

19
tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs

@ -11,8 +11,8 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodePng : BenchmarkBase public class EncodePng
{ {
// System.Drawing needs this. // System.Drawing needs this.
private Stream bmpStream; private Stream bmpStream;
@ -39,6 +39,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public void Cleanup() public void Cleanup()
{ {
this.bmpStream.Dispose(); this.bmpStream.Dispose();
this.bmpStream = null;
this.bmpCore.Dispose(); this.bmpCore.Dispose();
this.bmpDrawing.Dispose(); this.bmpDrawing.Dispose();
} }
@ -46,20 +47,16 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Benchmark(Baseline = true, Description = "System.Drawing Png")] [Benchmark(Baseline = true, Description = "System.Drawing Png")]
public void PngSystemDrawing() public void PngSystemDrawing()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ this.bmpDrawing.Save(memoryStream, ImageFormat.Png);
this.bmpDrawing.Save(memoryStream, ImageFormat.Png);
}
} }
[Benchmark(Description = "ImageSharp Png")] [Benchmark(Description = "ImageSharp Png")]
public void PngCore() public void PngCore()
{ {
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ var encoder = new PngEncoder { FilterMethod = PngFilterMethod.None };
var encoder = new PngEncoder { FilterMethod = PngFilterMethod.None }; this.bmpCore.SaveAsPng(memoryStream, encoder);
this.bmpCore.SaveAsPng(memoryStream, encoder);
}
} }
} }
} }

11
tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs

@ -2,23 +2,21 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using ImageMagick; using ImageMagick;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeTga : BenchmarkBase public class EncodeTga
{ {
private MagickImage tgaMagick; private MagickImage tgaMagick;
private Image<Rgba32> tga; private Image<Rgba32> tga;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[Params(TestImages.Tga.Bit24BottomLeft)] [Params(TestImages.Tga.Bit24BottomLeft)]
public string TestImage { get; set; } public string TestImage { get; set; }
@ -37,6 +35,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public void Cleanup() public void Cleanup()
{ {
this.tga.Dispose(); this.tga.Dispose();
this.tga = null;
this.tgaMagick.Dispose(); this.tgaMagick.Dispose();
} }

4
tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs

@ -10,8 +10,8 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class EncodeWebp : BenchmarkBase public class EncodeWebp
{ {
private MagickImage webpMagick; private MagickImage webpMagick;
private Image<Rgba32> webp; private Image<Rgba32> webp;

32
tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs

@ -1,32 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
public class GetSetPixel : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")]
public System.Drawing.Color ResizeSystemDrawing()
{
using (var source = new Bitmap(400, 400))
{
source.SetPixel(200, 200, System.Drawing.Color.White);
return source.GetPixel(200, 200);
}
}
[Benchmark(Description = "ImageSharp GetSet pixel")]
public Rgba32 ResizeCore()
{
using (var image = new Image<Rgba32>(400, 400))
{
image[200, 200] = Color.White;
return image[200, 200];
}
}
}
}

16
tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class CmykColorConversion : ColorConversionBenchmark public class CmykColorConversion : ColorConversionBenchmark
{ {
public CmykColorConversion() public CmykColorConversion()
@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void Scalar() public void Scalar()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromCmykBasic(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromCmykBasic(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVector8() public void SimdVector8()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromCmykVector8(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromCmykVector8(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVectorAvx2() public void SimdVectorAvx2()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromCmykAvx2(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromCmykAvx2(8).ConvertToRgba(values, this.Output);
} }
} }
} }

20
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -11,27 +11,27 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
public abstract class ColorConversionBenchmark public abstract class ColorConversionBenchmark
{ {
private readonly int componentCount; private readonly int componentCount;
protected Buffer2D<float>[] input;
protected Vector4[] output; public const int Count = 128;
protected ColorConversionBenchmark(int componentCount) protected ColorConversionBenchmark(int componentCount)
{ => this.componentCount = componentCount;
this.componentCount = componentCount;
}
public const int Count = 128; protected Buffer2D<float>[] Input { get; private set; }
protected Vector4[] Output { get; private set; }
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
this.input = CreateRandomValues(this.componentCount, Count); this.Input = CreateRandomValues(this.componentCount, Count);
this.output = new Vector4[Count]; this.Output = new Vector4[Count];
} }
[GlobalCleanup] [GlobalCleanup]
public void Cleanup() public void Cleanup()
{ {
foreach (Buffer2D<float> buffer in this.input) foreach (Buffer2D<float> buffer in this.Input)
{ {
buffer.Dispose(); buffer.Dispose();
} }

7
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs

@ -3,7 +3,6 @@
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
@ -11,7 +10,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeJpegParseStreamOnly public class DecodeJpegParseStreamOnly
{ {
[Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)] [Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)]
@ -23,9 +22,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ => this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
}
[Benchmark(Baseline = true, Description = "System.Drawing FULL")] [Benchmark(Baseline = true, Description = "System.Drawing FULL")]
public SDSize JpegSystemDrawing() public SDSize JpegSystemDrawing()

16
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs

@ -2,22 +2,20 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Collections.Generic; using System.Collections.Generic;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
using SDImage = System.Drawing.Image; using SDImage = System.Drawing.Image;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
/// <summary> /// <summary>
/// An expensive Jpeg benchmark, running on a wide range of input images, showing aggregate results. /// An expensive Jpeg benchmark, running on a wide range of input images,
/// showing aggregate results.
/// </summary> /// </summary>
[Config(typeof(MultiImageBenchmarkBase.Config))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => protected override IEnumerable<string> InputImageSubfoldersOrFiles =>
@ -35,14 +33,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark] [Benchmark]
public void ImageSharp() public void ImageSharp()
{ => this.ForEachStream(ms => Image.Load<Rgba32>(ms, new JpegDecoder()));
this.ForEachStream(ms => Image.Load<Rgba32>(ms, new JpegDecoder()));
}
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void SystemDrawing() public void SystemDrawing()
{ => this.ForEachStream(SDImage.FromStream);
this.ForEachStream(SDImage.FromStream);
}
} }
} }

20
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs

@ -3,11 +3,6 @@
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
@ -20,22 +15,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
/// <summary> /// <summary>
/// Image-specific Jpeg benchmarks /// Image-specific Jpeg benchmarks
/// </summary> /// </summary>
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class DecodeJpeg_ImageSpecific public class DecodeJpeg_ImageSpecific
{ {
public class Config : ManualConfig
{
public Config() => this.AddDiagnoser(MemoryDiagnoser.Default);
public class ShortClr : Benchmarks.Config
{
public ShortClr() =>
// Job.Default.With(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3),
this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3));
}
}
private byte[] jpegBytes; private byte[] jpegBytes;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);

32
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs

@ -1,23 +1,20 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using System.Drawing; public class EncodeJpeg
using System.Drawing.Imaging;
using System.IO;
using SixLabors.ImageSharp.Tests;
using CoreImage = SixLabors.ImageSharp.Image;
public class EncodeJpeg : BenchmarkBase
{ {
// System.Drawing needs this. // System.Drawing needs this.
private Stream bmpStream; private Stream bmpStream;
private Image bmpDrawing; private SDImage bmpDrawing;
private Image<Rgba32> bmpCore; private Image<Rgba32> bmpCore;
[GlobalSetup] [GlobalSetup]
@ -27,9 +24,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
const string TestImage = TestImages.Bmp.Car; const string TestImage = TestImages.Bmp.Car;
this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImage)); this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImage));
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream); this.bmpCore = Image.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0; this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream); this.bmpDrawing = SDImage.FromStream(this.bmpStream);
} }
} }
@ -37,6 +34,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
public void Cleanup() public void Cleanup()
{ {
this.bmpStream.Dispose(); this.bmpStream.Dispose();
this.bmpStream = null;
this.bmpCore.Dispose(); this.bmpCore.Dispose();
this.bmpDrawing.Dispose(); this.bmpDrawing.Dispose();
} }
@ -44,19 +42,15 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true, Description = "System.Drawing Jpeg")] [Benchmark(Baseline = true, Description = "System.Drawing Jpeg")]
public void JpegSystemDrawing() public void JpegSystemDrawing()
{ {
using (var stream = new MemoryStream()) using var stream = new MemoryStream();
{ this.bmpDrawing.Save(stream, ImageFormat.Jpeg);
this.bmpDrawing.Save(stream, ImageFormat.Jpeg);
}
} }
[Benchmark(Description = "ImageSharp Jpeg")] [Benchmark(Description = "ImageSharp Jpeg")]
public void JpegCore() public void JpegCore()
{ {
using (var stream = new MemoryStream()) using var stream = new MemoryStream();
{ this.bmpCore.SaveAsJpeg(stream);
this.bmpCore.SaveAsJpeg(stream);
}
} }
} }
} }

10
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Formats.Jpeg;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] // It's long enough to iterate through multiple files [Config(typeof(Config.ShortMultiFramework))]
public class EncodeJpegMultiple : MultiImageBenchmarkBase.WithImagesPreloaded public class EncodeJpegMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
@ -17,22 +17,18 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Description = "EncodeJpegMultiple - ImageSharp")] [Benchmark(Description = "EncodeJpegMultiple - ImageSharp")]
public void EncodeJpegImageSharp() public void EncodeJpegImageSharp()
{ => this.ForEachImageSharpImage((img, ms) =>
this.ForEachImageSharpImage((img, ms) =>
{ {
img.Save(ms, new JpegEncoder()); img.Save(ms, new JpegEncoder());
return null; return null;
}); });
}
[Benchmark(Baseline = true, Description = "EncodeJpegMultiple - System.Drawing")] [Benchmark(Baseline = true, Description = "EncodeJpegMultiple - System.Drawing")]
public void EncodeJpegSystemDrawing() public void EncodeJpegSystemDrawing()
{ => this.ForEachSystemDrawingImage((img, ms) =>
this.ForEachSystemDrawingImage((img, ms) =>
{ {
img.Save(ms, ImageFormat.Jpeg); img.Save(ms, ImageFormat.Jpeg);
return null; return null;
}); });
}
} }
} }

10
tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class GrayscaleColorConversion : ColorConversionBenchmark public class GrayscaleColorConversion : ColorConversionBenchmark
{ {
public GrayscaleColorConversion() public GrayscaleColorConversion()
@ -17,17 +17,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void Scalar() public void Scalar()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVectorAvx2() public void SimdVectorAvx2()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgba(values, this.Output);
} }
} }
} }

13
tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs

@ -1,15 +1,14 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class IdentifyJpeg public class IdentifyJpeg
{ {
private byte[] jpegBytes; private byte[] jpegBytes;
@ -31,11 +30,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark] [Benchmark]
public IImageInfo Identify() public IImageInfo Identify()
{ {
using (var memoryStream = new MemoryStream(this.jpegBytes)) using var memoryStream = new MemoryStream(this.jpegBytes);
{ var decoder = new JpegDecoder();
var decoder = new JpegDecoder(); return decoder.Identify(Configuration.Default, memoryStream);
return decoder.Identify(Configuration.Default, memoryStream);
}
} }
} }
} }

64
tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs

@ -6,9 +6,7 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
@ -17,7 +15,7 @@ using SixLabors.ImageSharp.Tests;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(MultiImageBenchmarkBase.Config))] [Config(typeof(Config.ShortMultiFramework))]
public class LoadResizeSave_Aggregate : MultiImageBenchmarkBase public class LoadResizeSave_Aggregate : MultiImageBenchmarkBase
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => protected override IEnumerable<string> InputImageSubfoldersOrFiles =>
@ -48,49 +46,43 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void SystemDrawing() public void SystemDrawing()
{ => this.ForEachStream(
this.ForEachStream(
sourceStream => sourceStream =>
{
using (var destStream = new MemoryStream(this.destBytes))
using (var source = System.Drawing.Image.FromStream(sourceStream))
using (var destination = new Bitmap(source.Width / 4, source.Height / 4))
{ {
using (var destStream = new MemoryStream(this.destBytes)) using (var g = Graphics.FromImage(destination))
using (var source = System.Drawing.Image.FromStream(sourceStream))
using (var destination = new Bitmap(source.Width / 4, source.Height / 4))
{ {
using (var g = Graphics.FromImage(destination)) g.InterpolationMode = InterpolationMode.HighQualityBicubic;
{ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingQuality = CompositingQuality.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.DrawImage(source, 0, 0, 400, 400);
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(source, 0, 0, 400, 400);
}
destination.Save(destStream, ImageFormat.Jpeg);
} }
return null; destination.Save(destStream, ImageFormat.Jpeg);
}); }
}
return null;
});
[Benchmark] [Benchmark]
public void ImageSharp() public void ImageSharp()
{ => this.ForEachStream(
this.ForEachStream(
sourceStream => sourceStream =>
{
using (var source = Image.Load<Rgba32>(
this.configuration,
sourceStream,
new JpegDecoder { IgnoreMetadata = true }))
{ {
using (var source = Image.Load<Rgba32>( using var destStream = new MemoryStream(this.destBytes);
this.configuration, source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4));
sourceStream, source.SaveAsJpeg(destStream);
new JpegDecoder { IgnoreMetadata = true })) }
{
using (var destStream = new MemoryStream(this.destBytes))
{
source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4));
source.SaveAsJpeg(destStream);
}
}
return null; return null;
}); });
}
} }
} }

32
tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs

@ -7,17 +7,15 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
using SDImage = System.Drawing.Image; using SDImage = System.Drawing.Image;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class LoadResizeSave_ImageSpecific public class LoadResizeSave_ImageSpecific
{ {
private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); private readonly Configuration configuration = new Configuration(new JpegConfigurationModule());
@ -32,6 +30,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr,
TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr,
TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr)] TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr)]
public string TestImage { get; set; } public string TestImage { get; set; }
[Params(false, true)] [Params(false, true)]
@ -51,28 +50,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void SystemDrawing() public void SystemDrawing()
{ {
using (var sourceStream = new MemoryStream(this.sourceBytes)) using var sourceStream = new MemoryStream(this.sourceBytes);
using (var destStream = new MemoryStream(this.destBytes)) using var destStream = new MemoryStream(this.destBytes);
using (var source = SDImage.FromStream(sourceStream)) using var source = SDImage.FromStream(sourceStream);
using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) using var destination = new Bitmap(source.Width / 4, source.Height / 4);
using (var g = Graphics.FromImage(destination))
{ {
using (var g = Graphics.FromImage(destination)) g.InterpolationMode = InterpolationMode.HighQualityBicubic;
{ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingQuality = CompositingQuality.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.DrawImage(source, 0, 0, 400, 400);
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(source, 0, 0, 400, 400);
}
destination.Save(destStream, ImageFormat.Jpeg);
} }
destination.Save(destStream, ImageFormat.Jpeg);
} }
[Benchmark] [Benchmark]
public void ImageSharp() public void ImageSharp()
{ {
var source = Image.Load(this.configuration, this.sourceBytes, new JpegDecoder { IgnoreMetadata = true }); using (var source = Image.Load(this.configuration, this.sourceBytes, new JpegDecoder { IgnoreMetadata = true }))
using (source)
using (var destStream = new MemoryStream(this.destBytes)) using (var destStream = new MemoryStream(this.destBytes))
{ {
source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4)); source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4));

14
tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class RgbColorConversion : ColorConversionBenchmark public class RgbColorConversion : ColorConversionBenchmark
{ {
public RgbColorConversion() public RgbColorConversion()
@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void Scalar() public void Scalar()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromRgbBasic(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromRgbBasic(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVector8() public void SimdVector8()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromRgbVector8(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromRgbVector8(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVectorAvx2() public void SimdVectorAvx2()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromRgbAvx2(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromRgbAvx2(8).ConvertToRgba(values, this.Output);
} }
} }
} }

19
tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs

@ -2,12 +2,11 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class YCbCrColorConversion : ColorConversionBenchmark public class YCbCrColorConversion : ColorConversionBenchmark
{ {
public YCbCrColorConversion() public YCbCrColorConversion()
@ -18,33 +17,33 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark] [Benchmark]
public void Scalar() public void Scalar()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgba(values, this.Output);
} }
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void SimdVector() public void SimdVector()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVector8() public void SimdVector8()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVectorAvx2() public void SimdVectorAvx2()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgba(values, this.Output);
} }
} }
} }

14
tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class YccKColorConverter : ColorConversionBenchmark public class YccKColorConverter : ColorConversionBenchmark
{ {
public YccKColorConverter() public YccKColorConverter()
@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void Scalar() public void Scalar()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYccKBasic(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYccKBasic(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVector8() public void SimdVector8()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYccKVector8(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYccKVector8(8).ConvertToRgba(values, this.Output);
} }
[Benchmark] [Benchmark]
public void SimdVectorAvx2() public void SimdVectorAvx2()
{ {
var values = new JpegColorConverter.ComponentValues(this.input, 0); var values = new JpegColorConverter.ComponentValues(this.Input, 0);
new JpegColorConverter.FromYccKAvx2(8).ConvertToRgba(values, this.output); new JpegColorConverter.FromYccKAvx2(8).ConvertToRgba(values, this.Output);
} }
} }
} }

112
tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs

@ -8,33 +8,18 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests; using SixLabors.ImageSharp.Tests;
using CoreImage = SixLabors.ImageSharp.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
public abstract class MultiImageBenchmarkBase public abstract class MultiImageBenchmarkBase
{ {
public class Config : ManualConfig
{
public Config() => this.AddDiagnoser(MemoryDiagnoser.Default);
public class ShortClr : Benchmarks.Config
{
public ShortClr() => this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2));
}
}
protected Dictionary<string, byte[]> FileNamesToBytes { get; set; } = new Dictionary<string, byte[]>(); protected Dictionary<string, byte[]> FileNamesToBytes { get; set; } = new Dictionary<string, byte[]>();
protected Dictionary<string, Image<Rgba32>> FileNamesToImageSharpImages { get; set; } = new Dictionary<string, Image<Rgba32>>(); protected Dictionary<string, Image<Rgba32>> FileNamesToImageSharpImages { get; set; } = new Dictionary<string, Image<Rgba32>>();
protected Dictionary<string, Bitmap> FileNamesToSystemDrawingImages { get; set; } = new Dictionary<string, System.Drawing.Bitmap>(); protected Dictionary<string, Bitmap> FileNamesToSystemDrawingImages { get; set; } = new Dictionary<string, Bitmap>();
/// <summary> /// <summary>
/// The values of this enum separate input files into categories. /// The values of this enum separate input files into categories.
@ -72,7 +57,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
/// <summary> /// <summary>
/// Gets folders containing files OR files to be processed by the benchmark. /// Gets folders containing files OR files to be processed by the benchmark.
/// </summary> /// </summary>
protected IEnumerable<string> AllFoldersOrFiles => this.InputImageSubfoldersOrFiles.Select(f => Path.Combine(this.BaseFolder, f)); protected IEnumerable<string> AllFoldersOrFiles
=> this.InputImageSubfoldersOrFiles.Select(f => Path.Combine(this.BaseFolder, f));
/// <summary> /// <summary>
/// Gets the large image threshold. /// Gets the large image threshold.
@ -83,19 +69,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
protected IEnumerable<KeyValuePair<string, T>> EnumeratePairsByBenchmarkSettings<T>( protected IEnumerable<KeyValuePair<string, T>> EnumeratePairsByBenchmarkSettings<T>(
Dictionary<string, T> input, Dictionary<string, T> input,
Predicate<T> checkIfSmall) Predicate<T> checkIfSmall)
{ => this.InputCategory switch
switch (this.InputCategory)
{ {
case InputImageCategory.AllImages: InputImageCategory.AllImages => input,
return input; InputImageCategory.SmallImagesOnly => input.Where(kv => checkIfSmall(kv.Value)),
case InputImageCategory.SmallImagesOnly: InputImageCategory.LargeImagesOnly => input.Where(kv => !checkIfSmall(kv.Value)),
return input.Where(kv => checkIfSmall(kv.Value)); _ => throw new ArgumentOutOfRangeException(),
case InputImageCategory.LargeImagesOnly: };
return input.Where(kv => !checkIfSmall(kv.Value));
default:
throw new ArgumentOutOfRangeException();
}
}
protected IEnumerable<KeyValuePair<string, byte[]>> FileNames2Bytes protected IEnumerable<KeyValuePair<string, byte[]>> FileNames2Bytes
=> =>
@ -150,17 +130,15 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
foreach (KeyValuePair<string, byte[]> kv in this.FileNames2Bytes) foreach (KeyValuePair<string, byte[]> kv in this.FileNames2Bytes)
{ {
using (var memoryStream = new MemoryStream(kv.Value)) using var memoryStream = new MemoryStream(kv.Value);
try
{ {
try object obj = operation(memoryStream);
{ (obj as IDisposable)?.Dispose();
object obj = operation(memoryStream); }
(obj as IDisposable)?.Dispose(); catch (Exception ex)
} {
catch (Exception ex) Console.WriteLine($"Operation on {kv.Key} failed with {ex.Message}");
{
Console.WriteLine($"Operation on {kv.Key} failed with {ex.Message}");
}
} }
} }
} }
@ -178,7 +156,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
using (var ms1 = new MemoryStream(bytes)) using (var ms1 = new MemoryStream(bytes))
{ {
this.FileNamesToImageSharpImages[fn] = CoreImage.Load<Rgba32>(ms1); this.FileNamesToImageSharpImages[fn] = Image.Load<Rgba32>(ms1);
} }
this.FileNamesToSystemDrawingImages[fn] = new Bitmap(new MemoryStream(bytes)); this.FileNamesToSystemDrawingImages[fn] = new Bitmap(new MemoryStream(bytes));
@ -191,7 +169,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
this.FileNamesToImageSharpImages, this.FileNamesToImageSharpImages,
img => img.Width * img.Height < this.LargeImageThresholdInPixels); img => img.Width * img.Height < this.LargeImageThresholdInPixels);
protected IEnumerable<KeyValuePair<string, System.Drawing.Bitmap>> FileNames2SystemDrawingImages protected IEnumerable<KeyValuePair<string, Bitmap>> FileNames2SystemDrawingImages
=> =>
this.EnumeratePairsByBenchmarkSettings( this.EnumeratePairsByBenchmarkSettings(
this.FileNamesToSystemDrawingImages, this.FileNamesToSystemDrawingImages,
@ -217,22 +195,20 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
protected void ForEachImageSharpImage(Func<Image<Rgba32>, MemoryStream, object> operation) protected void ForEachImageSharpImage(Func<Image<Rgba32>, MemoryStream, object> operation)
{ {
using (var workStream = new MemoryStream()) using var workStream = new MemoryStream();
{ this.ForEachImageSharpImage(
this.ForEachImageSharpImage( img =>
img => {
{ // ReSharper disable AccessToDisposedClosure
// ReSharper disable AccessToDisposedClosure object result = operation(img, workStream);
object result = operation(img, workStream); workStream.Seek(0, SeekOrigin.Begin);
workStream.Seek(0, SeekOrigin.Begin);
// ReSharper restore AccessToDisposedClosure
// ReSharper restore AccessToDisposedClosure return result;
return result; });
});
}
} }
protected void ForEachSystemDrawingImage(Func<System.Drawing.Bitmap, object> operation) protected void ForEachSystemDrawingImage(Func<Bitmap, object> operation)
{ {
foreach (KeyValuePair<string, Bitmap> kv in this.FileNames2SystemDrawingImages) foreach (KeyValuePair<string, Bitmap> kv in this.FileNames2SystemDrawingImages)
{ {
@ -248,21 +224,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
} }
} }
protected void ForEachSystemDrawingImage(Func<System.Drawing.Bitmap, MemoryStream, object> operation) protected void ForEachSystemDrawingImage(Func<Bitmap, MemoryStream, object> operation)
{ {
using (var workStream = new MemoryStream()) using var workStream = new MemoryStream();
{ this.ForEachSystemDrawingImage(
this.ForEachSystemDrawingImage( img =>
img => {
{ // ReSharper disable AccessToDisposedClosure
// ReSharper disable AccessToDisposedClosure object result = operation(img, workStream);
object result = operation(img, workStream); workStream.Seek(0, SeekOrigin.Begin);
workStream.Seek(0, SeekOrigin.Begin);
// ReSharper restore AccessToDisposedClosure
// ReSharper restore AccessToDisposedClosure return result;
return result; });
});
}
} }
} }
} }

2
tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4_Rgb24.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class FromVector4_Rgb24 : FromVector4<Rgb24> public class FromVector4_Rgb24 : FromVector4<Rgb24>
{ {
} }

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class ToVector4_Bgra32 : ToVector4<Bgra32> public class ToVector4_Bgra32 : ToVector4<Bgra32>
{ {
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgb24.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class ToVector4_Rgb24 : ToVector4<Rgb24> public class ToVector4_Rgb24 : ToVector4<Rgb24>
{ {
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]

8
tests/ImageSharp.Benchmarks/Config.cs

@ -35,12 +35,12 @@ namespace SixLabors.ImageSharp.Benchmarks
Job.Default.WithRuntime(CoreRuntime.Core31)); Job.Default.WithRuntime(CoreRuntime.Core31));
} }
public class ShortClr : Config public class ShortMultiFramework : Config
{ {
public ShortClr() => this.AddJob( public ShortMultiFramework() => this.AddJob(
Job.Default.WithRuntime(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), Job.Default.WithRuntime(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), Job.Default.WithRuntime(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
Job.Default.WithRuntime(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)); Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3));
} }
public class ShortCore31 : Config public class ShortCore31 : Config

2
tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs

@ -8,7 +8,7 @@ using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32;
namespace SixLabors.ImageSharp.Benchmarks.General namespace SixLabors.ImageSharp.Benchmarks.General
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class Adler32Benchmark public class Adler32Benchmark
{ {
private byte[] data; private byte[] data;

2
tests/ImageSharp.Benchmarks/General/CopyBuffers.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General
/// - Span.CopyTo() has terrible performance on classic .NET Framework /// - Span.CopyTo() has terrible performance on classic .NET Framework
/// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning) /// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning)
/// </summary> /// </summary>
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class CopyBuffers public class CopyBuffers
{ {
private byte[] destArray; private byte[] destArray;

2
tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs

@ -8,7 +8,7 @@ using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32;
namespace SixLabors.ImageSharp.Benchmarks.General namespace SixLabors.ImageSharp.Benchmarks.General
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class Crc32Benchmark public class Crc32Benchmark
{ {
private byte[] data; private byte[] data;

28
tests/ImageSharp.Benchmarks/General/GetSetPixel.cs

@ -0,0 +1,28 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks
{
public class GetSetPixel
{
[Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")]
public System.Drawing.Color GetSetSystemDrawing()
{
using var source = new Bitmap(400, 400);
source.SetPixel(200, 200, System.Drawing.Color.White);
return source.GetPixel(200, 200);
}
[Benchmark(Description = "ImageSharp GetSet pixel")]
public Rgba32 GetSetImageSharp()
{
using var image = new Image<Rgba32>(400, 400);
image[200, 200] = Color.White;
return image[200, 200];
}
}
}

2
tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Benchmarks.IO namespace SixLabors.ImageSharp.Benchmarks.IO
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class BufferedStreams public class BufferedStreams
{ {
private readonly byte[] buffer = CreateTestBytes(); private readonly byte[] buffer = CreateTestBytes();

2
tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs

@ -8,7 +8,7 @@ using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class UInt32ToSingle public class UInt32ToSingle
{ {
private float[] data; private float[] data;

2
tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs

@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortMultiFramework))]
public class WidenBytesToUInt32 public class WidenBytesToUInt32
{ {
private byte[] source; private byte[] source;

2
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -43,7 +43,7 @@
<Compile Remove="General\BasicMath\ModuloPowerOfTwoConstant.cs" /> <Compile Remove="General\BasicMath\ModuloPowerOfTwoConstant.cs" />
<Compile Remove="General\BasicMath\ModuloPowerOfTwoVariable.cs" /> <Compile Remove="General\BasicMath\ModuloPowerOfTwoVariable.cs" />
<Compile Remove="PixelBlenders\**" /> <Compile Remove="PixelBlenders\**" />
<Compile Remove="Samplers\Resize.cs" /> <Compile Remove="Processing\Resize.cs" />
</ItemGroup> </ItemGroup>
</Project> </Project>

86
tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs

@ -1,21 +1,17 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers; using System.Buffers;
using System.Numerics; using System.Numerics;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.PixelFormats.PixelBlenders; using SixLabors.ImageSharp.PixelFormats.PixelBlenders;
namespace SixLabors.ImageSharp.Benchmarks namespace SixLabors.ImageSharp.Benchmarks
{ {
using CoreSize = SixLabors.ImageSharp.Size; public class PorterDuffBulkVsPixel
public class PorterDuffBulkVsPixel : BenchmarkBase
{ {
private Configuration Configuration => Configuration.Default; private Configuration Configuration => Configuration.Default;
@ -30,23 +26,21 @@ namespace SixLabors.ImageSharp.Benchmarks
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (IMemoryOwner<Vector4> buffer = using IMemoryOwner<Vector4> buffer =
Configuration.Default.MemoryAllocator.Allocate<Vector4>(destination.Length * 3)) Configuration.Default.MemoryAllocator.Allocate<Vector4>(destination.Length * 3);
{ Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(this.Configuration, background, backgroundSpan); PixelOperations<TPixel>.Instance.ToVector4(this.Configuration, background, backgroundSpan);
PixelOperations<TPixel>.Instance.ToVector4(this.Configuration, source, sourceSpan); PixelOperations<TPixel>.Instance.ToVector4(this.Configuration, source, sourceSpan);
for (int i = 0; i < destination.Length; i++) for (int i = 0; i < destination.Length; i++)
{ {
destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.Configuration, destinationSpan, destination);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.Configuration, destinationSpan, destination);
} }
private void BulkPixelConvert<TPixel>( private void BulkPixelConvert<TPixel>(
@ -67,44 +61,36 @@ namespace SixLabors.ImageSharp.Benchmarks
} }
[Benchmark(Description = "ImageSharp BulkVectorConvert")] [Benchmark(Description = "ImageSharp BulkVectorConvert")]
public CoreSize BulkVectorConvert() public Size BulkVectorConvert()
{ {
using (var image = new Image<Rgba32>(800, 800)) using var image = new Image<Rgba32>(800, 800);
{ using IMemoryOwner<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width);
using (IMemoryOwner<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width)) amounts.GetSpan().Fill(1);
{
amounts.GetSpan().Fill(1);
Buffer2D<Rgba32> pixels = image.GetRootFramePixelBuffer(); Buffer2D<Rgba32> pixels = image.GetRootFramePixelBuffer();
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
{ {
Span<Rgba32> span = pixels.GetRowSpan(y); Span<Rgba32> span = pixels.GetRowSpan(y);
this.BulkVectorConvert(span, span, span, amounts.GetSpan()); this.BulkVectorConvert(span, span, span, amounts.GetSpan());
}
return new CoreSize(image.Width, image.Height);
}
} }
return new Size(image.Width, image.Height);
} }
[Benchmark(Description = "ImageSharp BulkPixelConvert")] [Benchmark(Description = "ImageSharp BulkPixelConvert")]
public CoreSize BulkPixelConvert() public Size BulkPixelConvert()
{ {
using (var image = new Image<Rgba32>(800, 800)) using var image = new Image<Rgba32>(800, 800);
using IMemoryOwner<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width);
amounts.GetSpan().Fill(1);
Buffer2D<Rgba32> pixels = image.GetRootFramePixelBuffer();
for (int y = 0; y < image.Height; y++)
{ {
using (IMemoryOwner<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width)) Span<Rgba32> span = pixels.GetRowSpan(y);
{ this.BulkPixelConvert(span, span, span, amounts.GetSpan());
amounts.GetSpan().Fill(1);
Buffer2D<Rgba32> pixels = image.GetRootFramePixelBuffer();
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> span = pixels.GetRowSpan(y);
this.BulkPixelConvert(span, span, span, amounts.GetSpan());
}
return new CoreSize(image.Width, image.Height);
}
} }
return new Size(image.Width, image.Height);
} }
} }
} }

8
tests/ImageSharp.Benchmarks/Samplers/BokehBlur.cs → tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs

@ -5,7 +5,7 @@ using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Samplers namespace SixLabors.ImageSharp.Benchmarks.Processing
{ {
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.MultiFramework))]
public class BokehBlur public class BokehBlur
@ -13,10 +13,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers
[Benchmark] [Benchmark]
public void Blur() public void Blur()
{ {
using (var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.White)) using var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.White);
{ image.Mutate(c => c.BokehBlur());
image.Mutate(c => c.BokehBlur());
}
} }
} }
} }

40
tests/ImageSharp.Benchmarks/Processing/Crop.cs

@ -0,0 +1,40 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using System.Drawing.Drawing2D;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SDRectangle = System.Drawing.Rectangle;
using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Processing
{
[Config(typeof(Config.MultiFramework))]
public class Crop
{
[Benchmark(Baseline = true, Description = "System.Drawing Crop")]
public SDSize CropSystemDrawing()
{
using var source = new Bitmap(800, 800);
using var destination = new Bitmap(100, 100);
using var graphics = Graphics.FromImage(destination);
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(source, new SDRectangle(0, 0, 100, 100), 0, 0, 100, 100, GraphicsUnit.Pixel);
return destination.Size;
}
[Benchmark(Description = "ImageSharp Crop")]
public Size CropImageSharp()
{
using var image = new Image<Rgba32>(800, 800);
image.Mutate(x => x.Crop(100, 100));
return new Size(image.Width, image.Height);
}
}
}

20
tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs → tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs

@ -1,18 +1,16 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks namespace SixLabors.ImageSharp.Benchmarks
{ {
using System.IO; [Config(typeof(Config.MultiFramework))]
public class DetectEdges
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Processing;
using CoreImage = SixLabors.ImageSharp.Image;
public class DetectEdges : BenchmarkBase
{ {
private Image<Rgba32> image; private Image<Rgba32> image;
@ -21,10 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks
{ {
if (this.image == null) if (this.image == null)
{ {
using (FileStream stream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp")) this.image = Image.Load<Rgba32>(File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car)));
{
this.image = CoreImage.Load<Rgba32>(stream);
}
} }
} }
@ -32,6 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks
public void Cleanup() public void Cleanup()
{ {
this.image.Dispose(); this.image.Dispose();
this.image = null;
} }
[Benchmark(Description = "ImageSharp DetectEdges")] [Benchmark(Description = "ImageSharp DetectEdges")]

20
tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs → tests/ImageSharp.Benchmarks/Processing/Diffuse.cs

@ -5,31 +5,27 @@ using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Samplers namespace SixLabors.ImageSharp.Benchmarks.Processing
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.MultiFramework))]
public class Diffuse public class Diffuse
{ {
[Benchmark] [Benchmark]
public Size DoDiffuse() public Size DoDiffuse()
{ {
using (var image = new Image<Rgba32>(Configuration.Default, 800, 800, Color.BlanchedAlmond)) using var image = new Image<Rgba32>(Configuration.Default, 800, 800, Color.BlanchedAlmond);
{ image.Mutate(x => x.Dither(KnownDitherings.FloydSteinberg));
image.Mutate(x => x.Dither(KnownDitherings.FloydSteinberg));
return image.Size(); return image.Size();
}
} }
[Benchmark] [Benchmark]
public Size DoDither() public Size DoDither()
{ {
using (var image = new Image<Rgba32>(Configuration.Default, 800, 800, Color.BlanchedAlmond)) using var image = new Image<Rgba32>(Configuration.Default, 800, 800, Color.BlanchedAlmond);
{ image.Mutate(x => x.Dither());
image.Mutate(x => x.Dither());
return image.Size(); return image.Size();
}
} }
} }
} }

6
tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs → tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs

@ -13,10 +13,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers
[Benchmark] [Benchmark]
public void Blur() public void Blur()
{ {
using (var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.White)) using var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.White);
{ image.Mutate(c => c.GaussianBlur());
image.Mutate(c => c.GaussianBlur());
}
} }
} }
} }

31
tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs

@ -10,8 +10,8 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Processing namespace SixLabors.ImageSharp.Benchmarks.Processing
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.MultiFramework))]
public class HistogramEqualization : BenchmarkBase public class HistogramEqualization
{ {
private Image<Rgba32> image; private Image<Rgba32> image;
@ -28,26 +28,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Processing
public void Cleanup() public void Cleanup()
{ {
this.image.Dispose(); this.image.Dispose();
this.image = null;
} }
[Benchmark(Description = "Global Histogram Equalization")] [Benchmark(Description = "Global Histogram Equalization")]
public void GlobalHistogramEqualization() public void GlobalHistogramEqualization()
{ => this.image.Mutate(img => img.HistogramEqualization(
this.image.Mutate(img => img.HistogramEqualization(new HistogramEqualizationOptions() new HistogramEqualizationOptions()
{ {
LuminanceLevels = 256, LuminanceLevels = 256,
Method = HistogramEqualizationMethod.Global Method = HistogramEqualizationMethod.Global
})); }));
}
[Benchmark(Description = "AdaptiveHistogramEqualization (Tile interpolation)")] [Benchmark(Description = "AdaptiveHistogramEqualization (Tile interpolation)")]
public void AdaptiveHistogramEqualization() public void AdaptiveHistogramEqualization()
{ => this.image.Mutate(img => img.HistogramEqualization(
this.image.Mutate(img => img.HistogramEqualization(new HistogramEqualizationOptions() new HistogramEqualizationOptions()
{ {
LuminanceLevels = 256, LuminanceLevels = 256,
Method = HistogramEqualizationMethod.AdaptiveTileInterpolation Method = HistogramEqualizationMethod.AdaptiveTileInterpolation
})); }));
}
} }
} }

36
tests/ImageSharp.Benchmarks/Samplers/Resize.cs → tests/ImageSharp.Benchmarks/Processing/Resize.cs

@ -4,27 +4,23 @@
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Globalization; using System.Globalization;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks namespace SixLabors.ImageSharp.Benchmarks
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.MultiFramework))]
#pragma warning disable SA1649 // File name should match first type name public abstract class Resize<TPixel>
public abstract class ResizeBenchmarkBase<TPixel>
#pragma warning restore SA1649 // File name should match first type name
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
protected readonly Configuration Configuration = new Configuration(new JpegConfigurationModule());
private Image<TPixel> sourceImage; private Image<TPixel> sourceImage;
private Bitmap sourceBitmap; private Bitmap sourceBitmap;
protected Configuration Configuration { get; } = new Configuration(new JpegConfigurationModule());
[Params("3032-400")] [Params("3032-400")]
public virtual string SourceToDest { get; set; } public virtual string SourceToDest { get; set; }
@ -96,12 +92,10 @@ namespace SixLabors.ImageSharp.Benchmarks
protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx); protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx);
} }
public class Resize_Bicubic_Rgba32 : ResizeBenchmarkBase<Rgba32> public class Resize_Bicubic_Rgba32 : Resize<Rgba32>
{ {
protected override void ExecuteResizeOperation(IImageProcessingContext ctx) protected override void ExecuteResizeOperation(IImageProcessingContext ctx)
{ => ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic);
ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic);
}
// RESULTS - 2019 April - ResizeWorker: // RESULTS - 2019 April - ResizeWorker:
// //
@ -143,12 +137,10 @@ namespace SixLabors.ImageSharp.Benchmarks
} }
} }
public class Resize_Bicubic_Bgra32 : ResizeBenchmarkBase<Bgra32> public class Resize_Bicubic_Bgra32 : Resize<Bgra32>
{ {
protected override void ExecuteResizeOperation(IImageProcessingContext ctx) protected override void ExecuteResizeOperation(IImageProcessingContext ctx)
{ => ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic);
ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic);
}
// RESULTS (2019 April): // RESULTS (2019 April):
// //
@ -171,12 +163,10 @@ namespace SixLabors.ImageSharp.Benchmarks
// 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | Core | 3032 | 400 | 96.96 ms | 7.899 ms | 0.4329 ms | 0.80 | - | - | - | 44512 B | // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | Core | 3032 | 400 | 96.96 ms | 7.899 ms | 0.4329 ms | 0.80 | - | - | - | 44512 B |
} }
public class Resize_Bicubic_Rgb24 : ResizeBenchmarkBase<Rgb24> public class Resize_Bicubic_Rgb24 : Resize<Rgb24>
{ {
protected override void ExecuteResizeOperation(IImageProcessingContext ctx) protected override void ExecuteResizeOperation(IImageProcessingContext ctx)
{ => ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic);
ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic);
}
// RESULTS (2019 April): // RESULTS (2019 April):
// //
@ -197,12 +187,10 @@ namespace SixLabors.ImageSharp.Benchmarks
// 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | Core | 3032 | 400 | 92.47 ms | 5.683 ms | 0.3115 ms | 0.78 | 0.01 | - | - | - | 44512 B | // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | Core | 3032 | 400 | 92.47 ms | 5.683 ms | 0.3115 ms | 0.78 | 0.01 | - | - | - | 44512 B |
} }
public class Resize_BicubicCompand_Rgba32 : ResizeBenchmarkBase<Rgba32> public class Resize_BicubicCompand_Rgba32 : Resize<Rgba32>
{ {
protected override void ExecuteResizeOperation(IImageProcessingContext ctx) protected override void ExecuteResizeOperation(IImageProcessingContext ctx)
{ => ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true);
ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true);
}
// RESULTS (2019 April): // RESULTS (2019 April):
// //

12
tests/ImageSharp.Benchmarks/Samplers/Rotate.cs → tests/ImageSharp.Benchmarks/Processing/Rotate.cs

@ -5,20 +5,18 @@ using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Samplers namespace SixLabors.ImageSharp.Benchmarks.Processing
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.MultiFramework))]
public class Rotate public class Rotate
{ {
[Benchmark] [Benchmark]
public Size DoRotate() public Size DoRotate()
{ {
using (var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.BlanchedAlmond)) using var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.BlanchedAlmond);
{ image.Mutate(x => x.Rotate(37.5F));
image.Mutate(x => x.Rotate(37.5F));
return image.Size(); return image.Size();
}
} }
} }
} }

12
tests/ImageSharp.Benchmarks/Samplers/Skew.cs → tests/ImageSharp.Benchmarks/Processing/Skew.cs

@ -5,20 +5,18 @@ using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Samplers namespace SixLabors.ImageSharp.Benchmarks.Processing
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.MultiFramework))]
public class Skew public class Skew
{ {
[Benchmark] [Benchmark]
public Size DoSkew() public Size DoSkew()
{ {
using (var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.BlanchedAlmond)) using var image = new Image<Rgba32>(Configuration.Default, 400, 400, Color.BlanchedAlmond);
{ image.Mutate(x => x.Skew(20, 10));
image.Mutate(x => x.Skew(20, 10));
return image.Size(); return image.Size();
}
} }
} }
} }

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

@ -1,45 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using System.Drawing.Drawing2D;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SDRectangle = System.Drawing.Rectangle;
using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks
{
[Config(typeof(Config.ShortClr))]
public class Crop : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing Crop")]
public SDSize CropSystemDrawing()
{
using (var source = new Bitmap(800, 800))
using (var destination = new Bitmap(100, 100))
using (var graphics = Graphics.FromImage(destination))
{
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(source, new SDRectangle(0, 0, 100, 100), 0, 0, 100, 100, GraphicsUnit.Pixel);
return destination.Size;
}
}
[Benchmark(Description = "ImageSharp Crop")]
public Size CropResizeCore()
{
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.Crop(100, 100));
return new Size(image.Width, image.Height);
}
}
}
}
Loading…
Cancel
Save