Browse Source

Merge remote-tracking branch 'origin/master' into af/resize-sandbox

# Conflicts:
#	tests/ImageSharp.Benchmarks/General/ArrayCopy.cs
af/merge-core
Anton Firszov 7 years ago
parent
commit
eb21b1dd6e
  1. 24
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  2. 13
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  3. 7
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  4. 5
      src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs
  5. 3
      src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs
  6. 2
      src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs
  7. 416
      src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
  8. 9
      tests/ImageSharp.Benchmarks/BenchmarkBase.cs
  9. 2
      tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs
  10. 4
      tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs
  11. 1
      tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs
  12. 4
      tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs
  13. 40
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs
  14. 8
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
  15. 18
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
  16. 18
      tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
  17. 12
      tests/ImageSharp.Benchmarks/Color/ColorEquality.cs
  18. 14
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs
  19. 15
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs
  20. 15
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs
  21. 14
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs
  22. 32
      tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
  23. 15
      tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs
  24. 17
      tests/ImageSharp.Benchmarks/Config.cs
  25. 38
      tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs
  26. 51
      tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs
  27. 35
      tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs
  28. 26
      tests/ImageSharp.Benchmarks/Drawing/DrawText.cs
  29. 32
      tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs
  30. 49
      tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs
  31. 24
      tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs
  32. 28
      tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs
  33. 14
      tests/ImageSharp.Benchmarks/General/Array2D.cs
  34. 14
      tests/ImageSharp.Benchmarks/General/ArrayReverse.cs
  35. 4
      tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
  36. 5
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs
  37. 2
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs
  38. 10
      tests/ImageSharp.Benchmarks/General/Vector4Constants.cs
  39. 8
      tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs
  40. 12
      tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs
  41. 14
      tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs
  42. 9
      tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
  43. 8
      tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs
  44. 10
      tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs
  45. 6
      tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs
  46. 12
      tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs
  47. 11
      tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
  48. 6
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  49. 13
      tests/ImageSharp.Benchmarks/Program.cs
  50. 42
      tests/ImageSharp.Benchmarks/Samplers/Crop.cs
  51. 6
      tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs
  52. 13
      tests/ImageSharp.Benchmarks/Samplers/Glow.cs
  53. 1
      tests/ImageSharp.Benchmarks/Samplers/Resize.cs
  54. 5
      tests/ImageSharp.Benchmarks/Samplers/Rotate.cs
  55. 5
      tests/ImageSharp.Benchmarks/Samplers/Skew.cs
  56. 5
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
  57. 168
      tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs
  58. 2
      tests/ImageSharp.Tests/TestImages.cs
  59. 3
      tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg
  60. 3
      tests/Images/Input/Png/low-variance.png

24
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -95,8 +95,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
// Quantize the image returning a palette.
QuantizedFrame<TPixel> quantized =
this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame);
QuantizedFrame<TPixel> quantized = null;
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
{
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
}
// Get the number of bits.
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
@ -133,7 +136,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Clean up.
quantized?.Dispose();
quantized = null;
// TODO: Write extension etc
stream.WriteByte(GifConstants.EndIntroducer);
@ -158,7 +160,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
using (QuantizedFrame<TPixel> paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame))
using (IFrameQuantizer<TPixel> palleteFrameQuantizer = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()))
using (QuantizedFrame<TPixel> paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame))
{
this.WriteImageData(paletteQuantized, stream);
}
@ -181,14 +184,17 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength
&& frameMetadata.ColorTableLength > 0)
{
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(
image.GetConfiguration(),
frameMetadata.ColorTableLength).QuantizeFrame(frame);
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration(), frameMetadata.ColorTableLength))
{
quantized = frameQuantizer.QuantizeFrame(frame);
}
}
else
{
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())
.QuantizeFrame(frame);
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
{
quantized = frameQuantizer.QuantizeFrame(frame);
}
}
}

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

@ -401,15 +401,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (this.ComponentCount == 3)
{
if (this.adobe.Equals(default) || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
{
return JpegColorSpace.YCbCr;
}
if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
if (!this.adobe.Equals(default) && this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
return JpegColorSpace.RGB;
}
// Some images are poorly encoded and contain incorrect colorspace transform metadata.
// We ignore that and always fall back to the default colorspace.
return JpegColorSpace.YCbCr;
}
if (this.ComponentCount == 4)
@ -419,7 +418,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
: JpegColorSpace.Cmyk;
}
JpegThrowHelper.ThrowImageFormatException($"Unsupported color mode. Max components 4; found {this.ComponentCount}");
JpegThrowHelper.ThrowImageFormatException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {this.ComponentCount}");
return default;
}

7
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -243,8 +243,11 @@ namespace SixLabors.ImageSharp.Formats.Png
}
// Create quantized frame returning the palette and set the bit depth.
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())
.QuantizeFrame(image.Frames.RootFrame);
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
{
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
}
byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
bits = Math.Max(bits, quantizedBits);

5
src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs

@ -98,6 +98,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
return quantizedFrame;
}
/// <inheritdoc/>
public virtual void Dispose()
{
}
/// <summary>
/// Execute the first pass through the pixels in the image to create the palette.
/// </summary>

3
src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
@ -10,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Provides methods to allow the execution of the quantization process on an image frame.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public interface IFrameQuantizer<TPixel>
public interface IFrameQuantizer<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
/// <summary>

2
src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs

@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>(configuration);
using (IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>(configuration))
using (QuantizedFrame<TPixel> quantized = executor.QuantizeFrame(source))
{
int paletteCount = quantized.Palette.Length - 1;

416
src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs

@ -11,6 +11,8 @@ using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
// TODO: Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case?
// (T, R, G, B, A, M2) could be grouped together! Investigate a ColorMoment struct.
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
/// <summary>
@ -36,20 +38,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
internal sealed class WuFrameQuantizer<TPixel> : FrameQuantizerBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
// TODO: The WuFrameQuantizer<TPixel> code is rising several questions:
// - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes ) JS. I'm afraid so.
// - Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case?
// (T, R, G, B, A, M2) could be grouped together!
// - It's a frequently used class, we need tests! (So we can optimize safely.) There are tests in the original!!! We should just adopt them!
// https://github.com/JeremyAnsel/JeremyAnsel.ColorQuant/blob/master/JeremyAnsel.ColorQuant/JeremyAnsel.ColorQuant.Tests/WuColorQuantizerTests.cs
// The following two variables determine the amount of bits to preserve when calculating the histogram.
// Reducing the value of these numbers the granularity of the color maps produced, making it much faster
// and using much less memory but potentially less accurate. Current results are very good though!
/// <summary>
/// The index bits.
/// The index bits. 6 in original code.
/// </summary>
private const int IndexBits = 5;
/// <summary>
/// The index alpha bits. Keep separate for now to allow easy adjustment.
/// The index alpha bits. 3 in original code.
/// </summary>
private const int IndexAlphaBits = 5;
@ -64,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1;
/// <summary>
/// The table length. Now 1185921.
/// The table length. Now 1185921. originally 2471625.
/// </summary>
private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount;
@ -96,7 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary>
/// Moment of <c>c^2*P(c)</c>.
/// </summary>
private IMemoryOwner<float> m2;
private IMemoryOwner<double> m2;
/// <summary>
/// Color space tag.
@ -149,28 +148,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
Guard.NotNull(image, nameof(image));
MemoryAllocator memoryAllocator = image.MemoryAllocator;
try
{
this.vwt = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmr = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmg = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmb = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vma = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.m2 = memoryAllocator.Allocate<float>(TableLength, AllocationOptions.Clean);
this.tag = memoryAllocator.Allocate<byte>(TableLength, AllocationOptions.Clean);
return base.QuantizeFrame(image);
}
finally
{
this.vwt?.Dispose();
this.vmr?.Dispose();
this.vmg?.Dispose();
this.vmb?.Dispose();
this.vma?.Dispose();
this.m2?.Dispose();
this.tag?.Dispose();
}
this.vwt = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmr = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmg = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmb = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vma = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.m2 = memoryAllocator.Allocate<double>(TableLength, AllocationOptions.Clean);
this.tag = memoryAllocator.Allocate<byte>(TableLength, AllocationOptions.Clean);
return base.QuantizeFrame(image);
}
/// <inheritdoc/>
public override void Dispose()
{
this.vwt?.Dispose();
this.vmr?.Dispose();
this.vmg?.Dispose();
this.vmb?.Dispose();
this.vma?.Dispose();
this.m2?.Dispose();
this.tag?.Dispose();
}
internal TPixel[] AotGetPalette() => this.GetPalette();
@ -275,9 +273,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetPaletteIndex(int r, int g, int b, int a)
{
return (r << ((IndexBits * 2) + IndexAlphaBits)) + (r << (IndexBits + IndexAlphaBits + 1))
+ (g << (IndexBits + IndexAlphaBits)) + (r << (IndexBits * 2)) + (r << (IndexBits + 1))
+ (g << IndexBits) + ((r + g + b) << IndexAlphaBits) + r + g + b + a;
return (r << ((IndexBits * 2) + IndexAlphaBits))
+ (r << (IndexBits + IndexAlphaBits + 1))
+ (g << (IndexBits + IndexAlphaBits))
+ (r << (IndexBits * 2))
+ (r << (IndexBits + 1))
+ (g << IndexBits)
+ ((r + g + b) << IndexAlphaBits)
+ r + g + b + a;
}
/// <summary>
@ -288,26 +291,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <returns>The result.</returns>
private static float Volume(ref Box cube, Span<long> moment)
{
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMax)]
- moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)];
}
/// <summary>
/// Computes part of Volume(cube, moment) that doesn't depend on r1, g1, or b1 (depending on direction).
/// Computes part of Volume(cube, moment) that doesn't depend on RMax, GMax, BMax, or AMax (depending on direction).
/// </summary>
/// <param name="cube">The cube.</param>
/// <param name="direction">The direction.</param>
@ -319,47 +322,47 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
// Red
case 3:
return -moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return -moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)];
// Green
case 2:
return -moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return -moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)];
// Blue
case 1:
return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return -moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)];
// Alpha
case 0:
return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return -moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)];
default:
throw new ArgumentOutOfRangeException(nameof(direction));
@ -367,7 +370,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
/// <summary>
/// Computes remainder of Volume(cube, moment), substituting position for r1, g1, or b1 (depending on direction).
/// Computes remainder of Volume(cube, moment), substituting position for RMax, GMax, BMax, or AMax (depending on direction).
/// </summary>
/// <param name="cube">The cube.</param>
/// <param name="direction">The direction.</param>
@ -380,47 +383,47 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
// Red
case 3:
return moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A0)]
- moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A0)]
- moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A1)]
- moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A0)];
return moment[GetPaletteIndex(position, cube.GMax, cube.BMax, cube.AMax)]
- moment[GetPaletteIndex(position, cube.GMax, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(position, cube.GMax, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(position, cube.GMax, cube.BMin, cube.AMin)]
- moment[GetPaletteIndex(position, cube.GMin, cube.BMax, cube.AMax)]
+ moment[GetPaletteIndex(position, cube.GMin, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(position, cube.GMin, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(position, cube.GMin, cube.BMin, cube.AMin)];
// Green
case 2:
return moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A0)]
- moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A1)]
- moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A0)];
return moment[GetPaletteIndex(cube.RMax, position, cube.BMax, cube.AMax)]
- moment[GetPaletteIndex(cube.RMax, position, cube.BMax, cube.AMin)]
- moment[GetPaletteIndex(cube.RMax, position, cube.BMin, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMax, position, cube.BMin, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, position, cube.BMax, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, position, cube.BMax, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, position, cube.BMin, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, position, cube.BMin, cube.AMin)];
// Blue
case 1:
return moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A0)]
- moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A0)]
- moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A1)]
- moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A0)];
return moment[GetPaletteIndex(cube.RMax, cube.GMax, position, cube.AMax)]
- moment[GetPaletteIndex(cube.RMax, cube.GMax, position, cube.AMin)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, position, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, position, cube.AMin)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, position, cube.AMax)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, position, cube.AMin)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, position, cube.AMax)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, position, cube.AMin)];
// Alpha
case 0:
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, position)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, position)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, position)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, position)]
- moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, position)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, position)]
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, position)]
- moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, position)];
return moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, position)]
- moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, position)]
- moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, position)]
+ moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, position)]
- moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, position)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, position)]
+ moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, position)]
- moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, position)];
default:
throw new ArgumentOutOfRangeException(nameof(direction));
@ -440,7 +443,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
Span<long> vmgSpan = this.vmg.GetSpan();
Span<long> vmbSpan = this.vmb.GetSpan();
Span<long> vmaSpan = this.vma.GetSpan();
Span<float> m2Span = this.m2.GetSpan();
Span<double> m2Span = this.m2.GetSpan();
// Build up the 3-D color histogram
// Loop through each row
@ -489,34 +492,34 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
Span<long> vmgSpan = this.vmg.GetSpan();
Span<long> vmbSpan = this.vmb.GetSpan();
Span<long> vmaSpan = this.vma.GetSpan();
Span<float> m2Span = this.m2.GetSpan();
Span<double> m2Span = this.m2.GetSpan();
using (IMemoryOwner<long> volume = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<long> volumeR = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<long> volumeG = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<long> volumeB = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<long> volumeA = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<float> volume2 = memoryAllocator.Allocate<float>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<double> volume2 = memoryAllocator.Allocate<double>(IndexCount * IndexAlphaCount))
using (IMemoryOwner<long> area = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IMemoryOwner<long> areaR = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IMemoryOwner<long> areaG = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IMemoryOwner<long> areaB = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IMemoryOwner<long> areaA = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IMemoryOwner<float> area2 = memoryAllocator.Allocate<float>(IndexAlphaCount))
using (IMemoryOwner<double> area2 = memoryAllocator.Allocate<double>(IndexAlphaCount))
{
Span<long> volumeSpan = volume.GetSpan();
Span<long> volumeRSpan = volumeR.GetSpan();
Span<long> volumeGSpan = volumeG.GetSpan();
Span<long> volumeBSpan = volumeB.GetSpan();
Span<long> volumeASpan = volumeA.GetSpan();
Span<float> volume2Span = volume2.GetSpan();
Span<double> volume2Span = volume2.GetSpan();
Span<long> areaSpan = area.GetSpan();
Span<long> areaRSpan = areaR.GetSpan();
Span<long> areaGSpan = areaG.GetSpan();
Span<long> areaBSpan = areaB.GetSpan();
Span<long> areaASpan = areaA.GetSpan();
Span<float> area2Span = area2.GetSpan();
Span<double> area2Span = area2.GetSpan();
for (int r = 1; r < IndexCount; r++)
{
@ -543,7 +546,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
long lineG = 0;
long lineB = 0;
long lineA = 0;
float line2 = 0;
double line2 = 0;
for (int a = 1; a < IndexAlphaCount; a++)
{
@ -592,35 +595,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary>
/// <param name="cube">The cube.</param>
/// <returns>The <see cref="float"/>.</returns>
private float Variance(ref Box cube)
private double Variance(ref Box cube)
{
float dr = Volume(ref cube, this.vmr.GetSpan());
float dg = Volume(ref cube, this.vmg.GetSpan());
float db = Volume(ref cube, this.vmb.GetSpan());
float da = Volume(ref cube, this.vma.GetSpan());
Span<float> m2Span = this.m2.GetSpan();
float xx =
m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
- m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
- m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)]
+ m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
- m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)]
+ m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
- m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
- m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)]
+ m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
- m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
Span<double> m2Span = this.m2.GetSpan();
double moment =
m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMax)]
- m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMin)]
- m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMax)]
+ m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)]
- m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMax)]
+ m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)]
+ m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)]
- m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)]
- m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMax)]
+ m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)]
+ m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)]
- m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)]
+ m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)]
- m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)]
- m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)]
+ m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)];
var vector = new Vector4(dr, dg, db, da);
return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.GetSpan()));
return moment - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.GetSpan()));
}
/// <summary>
@ -714,10 +717,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
float wholeA = Volume(ref set1, this.vma.GetSpan());
float wholeW = Volume(ref set1, this.vwt.GetSpan());
float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxb = this.Maximize(ref set1, 1, set1.B0 + 1, set1.B1, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxa = this.Maximize(ref set1, 0, set1.A0 + 1, set1.A1, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxr = this.Maximize(ref set1, 3, set1.RMin + 1, set1.RMax, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(ref set1, 2, set1.GMin + 1, set1.GMax, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxb = this.Maximize(ref set1, 1, set1.BMin + 1, set1.BMax, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxa = this.Maximize(ref set1, 0, set1.AMin + 1, set1.AMax, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW);
int dir;
@ -743,48 +746,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
dir = 0;
}
set2.R1 = set1.R1;
set2.G1 = set1.G1;
set2.B1 = set1.B1;
set2.A1 = set1.A1;
set2.RMax = set1.RMax;
set2.GMax = set1.GMax;
set2.BMax = set1.BMax;
set2.AMax = set1.AMax;
switch (dir)
{
// Red
case 3:
set2.R0 = set1.R1 = cutr;
set2.G0 = set1.G0;
set2.B0 = set1.B0;
set2.A0 = set1.A0;
set2.RMin = set1.RMax = cutr;
set2.GMin = set1.GMin;
set2.BMin = set1.BMin;
set2.AMin = set1.AMin;
break;
// Green
case 2:
set2.G0 = set1.G1 = cutg;
set2.R0 = set1.R0;
set2.B0 = set1.B0;
set2.A0 = set1.A0;
set2.GMin = set1.GMax = cutg;
set2.RMin = set1.RMin;
set2.BMin = set1.BMin;
set2.AMin = set1.AMin;
break;
// Blue
case 1:
set2.B0 = set1.B1 = cutb;
set2.R0 = set1.R0;
set2.G0 = set1.G0;
set2.A0 = set1.A0;
set2.BMin = set1.BMax = cutb;
set2.RMin = set1.RMin;
set2.GMin = set1.GMin;
set2.AMin = set1.AMin;
break;
// Alpha
case 0:
set2.A0 = set1.A1 = cuta;
set2.R0 = set1.R0;
set2.G0 = set1.G0;
set2.B0 = set1.B0;
set2.AMin = set1.AMax = cuta;
set2.RMin = set1.RMin;
set2.GMin = set1.GMin;
set2.BMin = set1.BMin;
break;
}
set1.Volume = (set1.R1 - set1.R0) * (set1.G1 - set1.G0) * (set1.B1 - set1.B0) * (set1.A1 - set1.A0);
set2.Volume = (set2.R1 - set2.R0) * (set2.G1 - set2.G0) * (set2.B1 - set2.B0) * (set2.A1 - set2.A0);
set1.Volume = (set1.RMax - set1.RMin) * (set1.GMax - set1.GMin) * (set1.BMax - set1.BMin) * (set1.AMax - set1.AMin);
set2.Volume = (set2.RMax - set2.RMin) * (set2.GMax - set2.GMin) * (set2.BMax - set2.BMin) * (set2.AMax - set2.AMin);
return true;
}
@ -798,13 +801,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
Span<byte> tagSpan = this.tag.GetSpan();
for (int r = cube.R0 + 1; r <= cube.R1; r++)
for (int r = cube.RMin + 1; r <= cube.RMax; r++)
{
for (int g = cube.G0 + 1; g <= cube.G1; g++)
for (int g = cube.GMin + 1; g <= cube.GMax; g++)
{
for (int b = cube.B0 + 1; b <= cube.B1; b++)
for (int b = cube.BMin + 1; b <= cube.BMax; b++)
{
for (int a = cube.A0 + 1; a <= cube.A1; a++)
for (int a = cube.AMin + 1; a <= cube.AMax; a++)
{
tagSpan[GetPaletteIndex(r, g, b, a)] = label;
}
@ -819,12 +822,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
private void BuildCube()
{
this.colorCube = new Box[this.colors];
float[] vv = new float[this.colors];
double[] vv = new double[this.colors];
ref Box cube = ref this.colorCube[0];
cube.R0 = cube.G0 = cube.B0 = cube.A0 = 0;
cube.R1 = cube.G1 = cube.B1 = IndexCount - 1;
cube.A1 = IndexAlphaCount - 1;
cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0;
cube.RMax = cube.GMax = cube.BMax = IndexCount - 1;
cube.AMax = IndexAlphaCount - 1;
int next = 0;
@ -839,13 +842,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
else
{
vv[next] = 0F;
vv[next] = 0D;
i--;
}
next = 0;
float temp = vv[0];
double temp = vv[0];
for (int k = 1; k <= i; k++)
{
if (vv[k] > temp)
@ -855,7 +858,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
}
if (temp <= 0F)
if (temp <= 0D)
{
this.colors = i + 1;
break;
@ -897,52 +900,83 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary>
/// Represents a box color cube.
/// </summary>
private struct Box
private struct Box : IEquatable<Box>
{
/// <summary>
/// Gets or sets the min red value, exclusive.
/// </summary>
public int R0;
public int RMin;
/// <summary>
/// Gets or sets the max red value, inclusive.
/// </summary>
public int R1;
public int RMax;
/// <summary>
/// Gets or sets the min green value, exclusive.
/// </summary>
public int G0;
public int GMin;
/// <summary>
/// Gets or sets the max green value, inclusive.
/// </summary>
public int G1;
public int GMax;
/// <summary>
/// Gets or sets the min blue value, exclusive.
/// </summary>
public int B0;
public int BMin;
/// <summary>
/// Gets or sets the max blue value, inclusive.
/// </summary>
public int B1;
public int BMax;
/// <summary>
/// Gets or sets the min alpha value, exclusive.
/// </summary>
public int A0;
public int AMin;
/// <summary>
/// Gets or sets the max alpha value, inclusive.
/// </summary>
public int A1;
public int AMax;
/// <summary>
/// Gets or sets the volume.
/// </summary>
public int Volume;
/// <inheritdoc/>
public override bool Equals(object obj) => obj is Box box && this.Equals(box);
/// <inheritdoc/>
public bool Equals(Box other) =>
this.RMin == other.RMin
&& this.RMax == other.RMax
&& this.GMin == other.GMin
&& this.GMax == other.GMax
&& this.BMin == other.BMin
&& this.BMax == other.BMax
&& this.AMin == other.AMin
&& this.AMax == other.AMax
&& this.Volume == other.Volume;
/// <inheritdoc/>
public override int GetHashCode()
{
HashCode hash = default;
hash.Add(this.RMin);
hash.Add(this.RMax);
hash.Add(this.GMin);
hash.Add(this.GMax);
hash.Add(this.BMin);
hash.Add(this.BMax);
hash.Add(this.AMin);
hash.Add(this.AMax);
hash.Add(this.Volume);
return hash.ToHashCode();
}
}
}
}

9
tests/ImageSharp.Benchmarks/BenchmarkBase.cs

@ -1,7 +1,8 @@
namespace SixLabors.ImageSharp.Benchmarks
{
using SixLabors.ImageSharp.Formats;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Benchmarks
{
/// <summary>
/// The image benchmark base class.
/// </summary>
@ -15,4 +16,4 @@
// Add Image Formats
}
}
}
}

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

@ -54,4 +54,4 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
}
}
}
}
}

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

@ -1,7 +1,5 @@
// <copyright file="DecodePng.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.IO;
using System.Runtime.CompilerServices;

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

@ -11,7 +11,6 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class DecodePng : BenchmarkBase
{

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

@ -1,7 +1,5 @@
// <copyright file="ImageBenchmarkTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// This file contains small, cheap and "unit test" benchmarks to test MultiImageBenchmarkBase.
// Need this because there are no real test cases for the common benchmark utility stuff.

40
tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs

@ -364,22 +364,30 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
ref Vector4 dTopLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset));
ref Vector4 dBottomLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset + destStride));
var xyLeft = new Vector4(sLeft.X);
xyLeft.Z = sLeft.Y;
xyLeft.W = sLeft.Y;
var zwLeft = new Vector4(sLeft.Z);
zwLeft.Z = sLeft.W;
zwLeft.W = sLeft.W;
var xyRight = new Vector4(sRight.X);
xyRight.Z = sRight.Y;
xyRight.W = sRight.Y;
var zwRight = new Vector4(sRight.Z);
zwRight.Z = sRight.W;
zwRight.W = sRight.W;
var xyLeft = new Vector4(sLeft.X)
{
Z = sLeft.Y,
W = sLeft.Y
};
var zwLeft = new Vector4(sLeft.Z)
{
Z = sLeft.W,
W = sLeft.W
};
var xyRight = new Vector4(sRight.X)
{
Z = sRight.Y,
W = sRight.Y
};
var zwRight = new Vector4(sRight.Z)
{
Z = sRight.W,
W = sRight.W
};
dTopLeft = xyLeft;
Unsafe.Add(ref dTopLeft, 1) = zwLeft;
Unsafe.Add(ref dTopLeft, 2) = xyRight;

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

@ -5,6 +5,7 @@ using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Jobs;
using SixLabors.ImageSharp.Formats.Jpeg;
@ -26,8 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
public Config()
{
// Uncomment if you want to use any of the diagnoser
this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser());
this.Add(MemoryDiagnoser.Default);
}
public class ShortClr : Benchmarks.Config
@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
public ShortClr()
{
this.Add(
//Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3),
Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3)
//Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3),
Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3)
);
}
}

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

@ -1,18 +1,16 @@
// <copyright file="EncodeJpeg.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using CoreImage = SixLabors.ImageSharp.Image;
public class EncodeJpeg : BenchmarkBase
@ -45,19 +43,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Baseline = true, Description = "System.Drawing Jpeg")]
public void JpegSystemDrawing()
{
using (var memoryStream = new MemoryStream())
using (var stream = new MemoryStream())
{
this.bmpDrawing.Save(memoryStream, ImageFormat.Jpeg);
this.bmpDrawing.Save(stream, ImageFormat.Jpeg);
}
}
[Benchmark(Description = "ImageSharp Jpeg")]
public void JpegCore()
{
using (var memoryStream = new MemoryStream())
using (var stream = new MemoryStream())
{
this.bmpCore.SaveAsJpeg(memoryStream);
this.bmpCore.SaveAsJpeg(stream);
}
}
}
}
}

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

@ -1,7 +1,5 @@
// <copyright file="MultiImageBenchmarkBase.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
@ -18,7 +16,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using SixLabors.ImageSharp.Tests;
using CoreImage = ImageSharp.Image;
@ -30,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public Config()
{
// Uncomment if you want to use any of the diagnoser
this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser());
this.Add(MemoryDiagnoser.Default);
}
public class ShortClr : Benchmarks.Config
@ -38,7 +36,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public ShortClr()
{
this.Add(
Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithTargetCount(2)
Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2)
);
}
}
@ -47,7 +45,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
protected Dictionary<string, byte[]> FileNamesToBytes = new Dictionary<string, byte[]>();
protected Dictionary<string, Image<Rgba32>> FileNamesToImageSharpImages = new Dictionary<string, Image<Rgba32>>();
protected Dictionary<string, System.Drawing.Bitmap> FileNamesToSystemDrawingImages = new Dictionary<string, System.Drawing.Bitmap>();
protected Dictionary<string, Bitmap> FileNamesToSystemDrawingImages = new Dictionary<string, System.Drawing.Bitmap>();
/// <summary>
/// The values of this enum separate input files into categories
@ -152,7 +150,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
foreach (KeyValuePair<string, byte[]> kv in this.FileNames2Bytes)
{
using (MemoryStream memoryStream = new MemoryStream(kv.Value))
using (var memoryStream = new MemoryStream(kv.Value))
{
try
{
@ -179,7 +177,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
byte[] bytes = kv.Value;
string fn = kv.Key;
using (MemoryStream ms1 = new MemoryStream(bytes))
using (var ms1 = new MemoryStream(bytes))
{
this.FileNamesToImageSharpImages[fn] = CoreImage.Load<Rgba32>(ms1);
@ -223,7 +221,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
protected void ForEachImageSharpImage(Func<Image<Rgba32>, MemoryStream, object> operation)
{
using (MemoryStream workStream = new MemoryStream())
using (var workStream = new MemoryStream())
{
this.ForEachImageSharpImage(

12
tests/ImageSharp.Benchmarks/Color/ColorEquality.cs

@ -1,14 +1,12 @@
// <copyright file="ColorEquality.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks
{
using SystemColor = System.Drawing.Color;
public class ColorEquality

14
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs

@ -1,13 +1,13 @@
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using Colourful;
using Colourful.Conversion;
using Colourful;
using Colourful.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
public class ColorspaceCieXyzToCieLabConvert
{
private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);

15
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs

@ -1,13 +1,13 @@
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using Colourful;
using Colourful.Conversion;
using Colourful;
using Colourful.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
public class ColorspaceCieXyzToHunterLabConvert
{
private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);
@ -18,7 +18,6 @@
private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter();
[Benchmark(Baseline = true, Description = "Colourful Convert")]
public double ColourfulConvert()
{

15
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs

@ -1,13 +1,13 @@
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using Colourful;
using Colourful.Conversion;
using Colourful;
using Colourful.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
public class ColorspaceCieXyzToLmsConvert
{
private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);
@ -18,7 +18,6 @@
private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter();
[Benchmark(Baseline = true, Description = "Colourful Convert")]
public double ColourfulConvert()
{

14
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs

@ -1,13 +1,13 @@
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using Colourful;
using Colourful.Conversion;
using Colourful;
using Colourful.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
public class ColorspaceCieXyzToRgbConvert
{
private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);

32
tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs

@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Benchmarks
OnStackInputCache.Byte input = OnStackInputCache.Byte.Create(this.inputSourceRGB);
// On-stack output:
Result result = default(Result);
Result result = default;
float* yPtr = (float*)&result.Y;
float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr;
@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Benchmarks
OnStackInputCache.Byte input = OnStackInputCache.Byte.Create(this.inputSourceRGB);
// On-stack output:
Result result = default(Result);
Result result = default;
float* yPtr = (float*)&result.Y;
float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr;
@ -194,15 +194,15 @@ namespace SixLabors.ImageSharp.Benchmarks
// Copy the input to the stack:
// On-stack output:
Result result = default(Result);
Result result = default;
float* yPtr = (float*)&result.Y;
float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr;
// end of code-bloat block :)
Vector<int> yCoeffs = new Vector<int>(ScaledCoeffs.Y);
Vector<int> cbCoeffs = new Vector<int>(ScaledCoeffs.Cb);
Vector<int> crCoeffs = new Vector<int>(ScaledCoeffs.Cr);
var yCoeffs = new Vector<int>(ScaledCoeffs.Y);
var cbCoeffs = new Vector<int>(ScaledCoeffs.Cb);
var crCoeffs = new Vector<int>(ScaledCoeffs.Cr);
for (int i = 0; i < this.inputSourceRGB.Length; i++)
{
@ -240,23 +240,23 @@ namespace SixLabors.ImageSharp.Benchmarks
// Copy the input to the stack:
// On-stack output:
Result result = default(Result);
Result result = default;
float* yPtr = (float*)&result.Y;
float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr;
// end of code-bloat block :)
Vector<int> yCoeffs = new Vector<int>(ScaledCoeffs.Y);
Vector<int> cbCoeffs = new Vector<int>(ScaledCoeffs.Cb);
Vector<int> crCoeffs = new Vector<int>(ScaledCoeffs.Cr);
var yCoeffs = new Vector<int>(ScaledCoeffs.Y);
var cbCoeffs = new Vector<int>(ScaledCoeffs.Cb);
var crCoeffs = new Vector<int>(ScaledCoeffs.Cr);
Vector<int> leftY = new Vector<int>(ScaledCoeffs.SelectLeft.Y);
Vector<int> leftCb = new Vector<int>(ScaledCoeffs.SelectLeft.Cb);
Vector<int> leftCr = new Vector<int>(ScaledCoeffs.SelectLeft.Cr);
var leftY = new Vector<int>(ScaledCoeffs.SelectLeft.Y);
var leftCb = new Vector<int>(ScaledCoeffs.SelectLeft.Cb);
var leftCr = new Vector<int>(ScaledCoeffs.SelectLeft.Cr);
Vector<int> rightY = new Vector<int>(ScaledCoeffs.SelectRight.Y);
Vector<int> rightCb = new Vector<int>(ScaledCoeffs.SelectRight.Cb);
Vector<int> rightCr = new Vector<int>(ScaledCoeffs.SelectRight.Cr);
var rightY = new Vector<int>(ScaledCoeffs.SelectRight.Y);
var rightCb = new Vector<int>(ScaledCoeffs.SelectRight.Cb);
var rightCr = new Vector<int>(ScaledCoeffs.SelectRight.Cr);
for (int i = 0; i < this.inputSourceRGB.Length; i++)
{

15
tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs

@ -1,13 +1,13 @@
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using Colourful;
using Colourful.Conversion;
using Colourful;
using Colourful.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{
public class RgbWorkingSpaceAdapt
{
private static readonly Rgb Rgb = new Rgb(0.206162F, 0.260277F, 0.746717F, RgbWorkingSpaces.WideGamutRgb);
@ -18,7 +18,6 @@
private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter { TargetRGBWorkingSpace = RGBWorkingSpaces.sRGB };
[Benchmark(Baseline = true, Description = "Colourful Adapt")]
public RGBColor ColourfulConvert()
{

17
tests/ImageSharp.Benchmarks/Config.cs

@ -1,20 +1,17 @@
// <copyright file="Config.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Jobs;
namespace SixLabors.ImageSharp.Benchmarks
{
using BenchmarkDotNet.Jobs;
public class Config : ManualConfig
{
public Config()
{
// Uncomment if you want to use any of the diagnoser
this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser());
this.Add(MemoryDiagnoser.Default);
}
public class ShortClr : Config
@ -22,9 +19,9 @@ namespace SixLabors.ImageSharp.Benchmarks
public ShortClr()
{
this.Add(
Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3),
Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3)
);
Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)
);
}
}
}

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

@ -1,7 +1,5 @@
// <copyright file="DrawBeziers.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -19,27 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Baseline = true, Description = "System.Drawing Draw Beziers")]
public void DrawPathSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (Graphics graphics = Graphics.FromImage(destination))
using (var pen = new Pen(Color.HotPink, 10))
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(System.Drawing.Color.HotPink, 10))
{
graphics.DrawBeziers(pen, new[] {
new PointF(10, 500),
new PointF(30, 10),
new PointF(240, 30),
new PointF(300, 500)
});
}
graphics.DrawBeziers(pen, new[] {
new PointF(10, 500),
new PointF(30, 10),
new PointF(240, 30),
new PointF(300, 500)
});
}
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
@ -47,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Beziers")]
public void DrawLinesCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.DrawBeziers(
Rgba32.HotPink,
@ -59,9 +55,9 @@ namespace SixLabors.ImageSharp.Benchmarks
new Vector2(300, 500)
}));
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
image.SaveAsBmp(ms);
image.SaveAsBmp(stream);
}
}
}

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

@ -1,44 +1,41 @@
// <copyright file="DrawLines.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks
{
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Numerics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks
{
public class DrawLines : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing Draw Lines")]
public void DrawPathSystemDrawing()
{
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
using (var graphics = Graphics.FromImage(destination))
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(Color.HotPink, 10))
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(System.Drawing.Color.HotPink, 10))
{
graphics.DrawLines(pen, new[] {
new PointF(10, 10),
new PointF(550, 50),
new PointF(200, 400)
});
}
graphics.DrawLines(pen, new[] {
new PointF(10, 10),
new PointF(550, 50),
new PointF(200, 400)
});
}
using (var ms = new MemoryStream())
using (var stream = new MemoryStream())
{
destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
@ -57,9 +54,9 @@ namespace SixLabors.ImageSharp.Benchmarks
new Vector2(200, 400)
}));
using (var ms = new MemoryStream())
using (var stream = new MemoryStream())
{
image.SaveAsBmp(ms);
image.SaveAsBmp(stream);
}
}
}

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

@ -1,7 +1,5 @@
// <copyright file="Crop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -19,26 +17,23 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Baseline = true, Description = "System.Drawing Draw Polygon")]
public void DrawPolygonSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
using (Graphics graphics = Graphics.FromImage(destination))
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(Color.HotPink, 10))
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(System.Drawing.Color.HotPink, 10))
{
graphics.DrawPolygon(pen, new[] {
new PointF(10, 10),
new PointF(550, 50),
new PointF(200, 400)
});
}
graphics.DrawPolygon(pen, new[] {
new PointF(10, 10),
new PointF(550, 50),
new PointF(200, 400)
});
}
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
@ -46,7 +41,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Polygon")]
public void DrawPolygonCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.DrawPolygon(
Rgba32.HotPink,
@ -57,7 +52,7 @@ namespace SixLabors.ImageSharp.Benchmarks
new Vector2(200, 400)
}));
using (MemoryStream ms = new MemoryStream())
using (var ms = new MemoryStream())
{
image.SaveAsBmp(ms);
}

26
tests/ImageSharp.Benchmarks/Drawing/DrawText.cs

@ -1,7 +1,5 @@
// <copyright file="Crop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -14,11 +12,9 @@ using SixLabors.ImageSharp.Processing.Processors.Text;
namespace SixLabors.ImageSharp.Benchmarks
{
[MemoryDiagnoser]
public class DrawText : BenchmarkBase
{
[Params(10, 100)]
public int TextIterations { get; set; }
public string TextPhrase { get; set; } = "Hello World";
@ -28,26 +24,22 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Baseline = true, Description = "System.Drawing Draw Text")]
public void DrawTextSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
using (Graphics graphics = Graphics.FromImage(destination))
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var font = new Font("Arial", 12, GraphicsUnit.Point))
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var font = new Font("Arial", 12, GraphicsUnit.Point))
{
graphics.DrawString(TextToRender, font, System.Drawing.Brushes.HotPink, new RectangleF(10, 10, 780, 780));
}
graphics.DrawString(TextToRender, font, System.Drawing.Brushes.HotPink, new RectangleF(10, 10, 780, 780));
}
}
}
[Benchmark(Description = "ImageSharp Draw Text - Cached Glyphs")]
public void DrawTextCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12);
image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor<Rgba32>(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10))));
@ -57,7 +49,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Text - Nieve")]
public void DrawTextCoreOld()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12);
image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10)));

32
tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs

@ -1,7 +1,5 @@
// <copyright file="Crop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -13,34 +11,28 @@ using SixLabors.ImageSharp.Processing.Processors.Text;
namespace SixLabors.ImageSharp.Benchmarks
{
[MemoryDiagnoser]
public class DrawTextOutline : BenchmarkBase
{
[Params(10, 100)]
public int TextIterations { get; set; }
public string TextPhrase { get; set; } = "Hello World";
public string TextToRender => string.Join(" ", Enumerable.Repeat(TextPhrase, TextIterations));
[Benchmark(Baseline = true, Description = "System.Drawing Draw Text Outline")]
public void DrawTextSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
using (Graphics graphics = Graphics.FromImage(destination))
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(Color.HotPink, 10))
using (var font = new Font("Arial", 12, GraphicsUnit.Point))
using (var gp = new GraphicsPath())
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(System.Drawing.Color.HotPink, 10))
using (var font = new Font("Arial", 12, GraphicsUnit.Point))
using (var gp = new GraphicsPath())
{
gp.AddString(TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat());
graphics.DrawPath(pen, gp);
}
gp.AddString(TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat());
graphics.DrawPath(pen, gp);
}
}
}
@ -48,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Text Outline - Cached Glyphs")]
public void DrawTextCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12);
image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor<Rgba32>(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10))));
@ -58,7 +50,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Draw Text Outline - Nieve")]
public void DrawTextCoreOld()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12);
image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10)));

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

@ -1,7 +1,5 @@
// <copyright file="FillPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -21,31 +19,30 @@ namespace SixLabors.ImageSharp.Benchmarks
public FillPolygon()
{
this.shape = new Polygon(new LinearLineSegment(new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)));
this.shape = new Polygon(new LinearLineSegment(
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)));
}
[Benchmark(Baseline = true, Description = "System.Drawing Fill Polygon")]
public void DrawSolidPolygonSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.FillPolygon(System.Drawing.Brushes.HotPink,
new[] {
new Point(10, 10),
new Point(550, 50),
new Point(200, 400)
});
using (Graphics graphics = Graphics.FromImage(destination))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.FillPolygon(System.Drawing.Brushes.HotPink,
new[]
{
new Point(10, 10),
new Point(550, 50),
new Point(200, 400)
});
}
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
@ -53,7 +50,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill Polygon")]
public void DrawSolidPolygonCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.FillPolygon(
Rgba32.HotPink,
@ -63,9 +60,9 @@ namespace SixLabors.ImageSharp.Benchmarks
new Vector2(200, 400)
}));
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
image.SaveAsBmp(ms);
image.SaveAsBmp(stream);
}
}
}
@ -73,15 +70,15 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill Polygon - cached shape")]
public void DrawSolidPolygonCoreCahced()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.Fill(
Rgba32.HotPink,
this.shape));
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
image.SaveAsBmp(ms);
image.SaveAsBmp(stream);
}
}
}

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

@ -1,7 +1,5 @@
// <copyright file="Crop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -15,22 +13,18 @@ using CoreSize = SixLabors.Primitives.Size;
namespace SixLabors.ImageSharp.Benchmarks
{
public class FillRectangle : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing Fill Rectangle")]
public Size FillRectangleSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
using (Graphics graphics = Graphics.FromImage(destination))
{
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.FillRectangle(System.Drawing.Brushes.HotPink, new Rectangle(10, 10, 190, 140));
}
graphics.InterpolationMode = InterpolationMode.Default;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.FillRectangle(System.Drawing.Brushes.HotPink, new Rectangle(10, 10, 190, 140));
return destination.Size;
}
}
@ -38,7 +32,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill Rectangle")]
public CoreSize FillRactangleCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.Fill(Rgba32.HotPink, new CoreRectangle(10, 10, 190, 140)));
@ -49,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill Rectangle - As Polygon")]
public CoreSize FillPolygonCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.FillPolygon(
Rgba32.HotPink,

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

@ -1,7 +1,5 @@
// <copyright file="FillWithPattern.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.Drawing.Drawing2D;
@ -21,19 +19,19 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Baseline = true, Description = "System.Drawing Fill with Pattern")]
public void DrawPatternPolygonSystemDrawing()
{
using (Bitmap destination = new Bitmap(800, 800))
using (var destination = new Bitmap(800, 800))
using (var graphics = Graphics.FromImage(destination))
{
using (Graphics graphics = Graphics.FromImage(destination))
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.HotPink))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.HotPink))
{
graphics.FillRectangle(brush, new Rectangle(0, 0, 800, 800)); // can't find a way to flood fill with a brush
}
graphics.FillRectangle(brush, new Rectangle(0, 0, 800, 800)); // can't find a way to flood fill with a brush
}
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
@ -41,13 +39,13 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Fill with Pattern")]
public void DrawPatternPolygon3Core()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.Fill(CoreBrushes.BackwardDiagonal(Rgba32.HotPink)));
using (MemoryStream ms = new MemoryStream())
using (var stream = new MemoryStream())
{
image.SaveAsBmp(ms);
image.SaveAsBmp(stream);
}
}
}

14
tests/ImageSharp.Benchmarks/General/Array2D.cs

@ -1,16 +1,14 @@
// <copyright file="Array2D.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System;
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Benchmarks.General
{
/**
* Method | Count | Mean | Error | StdDev | Scaled | ScaledSD |
-------------------------------------------- |------ |---------:|---------:|---------:|-------:|---------:|

14
tests/ImageSharp.Benchmarks/General/ArrayReverse.cs

@ -1,14 +1,12 @@
// <copyright file="ArrayReverse.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System;
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General
{
public class ArrayReverse
{
[Params(4, 16, 32)]
@ -58,4 +56,4 @@ namespace SixLabors.ImageSharp.Benchmarks.General
}
}
}
}
}

4
tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs

@ -1,7 +1,5 @@
// <copyright file="Clamp.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System;
using System.Runtime.CompilerServices;

5
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs

@ -1,7 +1,4 @@
// ReSharper disable InconsistentNaming
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;

2
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs

@ -3,8 +3,6 @@ using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertToVector4

10
tests/ImageSharp.Benchmarks/General/Vector4Constants.cs

@ -1,10 +1,10 @@
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System;
using System.Numerics;
using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General
{
/// <summary>
/// Has it any effect on performance to store SIMD constants as static readonly fields? Is it OK to always inline them?
/// Spoiler: the difference seems to be statistically insignificant!

8
tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
public class BitwiseOrUInt32
{
private uint[] input;

12
tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
public class DivFloat
{
private float[] input;
@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
[Benchmark]
public void Simd()
{
Vector<float> v = new Vector<float>(this.testValue);
var v = new Vector<float>(this.testValue);
for (int i = 0; i < this.input.Length; i += Vector<uint>.Count)
{
Vector<float> a = new Vector<float>(this.input, i);
var a = new Vector<float>(this.input, i);
a = a / v;
a.CopyTo(this.result, i);
}

14
tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
public class DivUInt32
{
private uint[] input;
@ -32,6 +32,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
public void Standard()
{
uint v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
{
this.result[i] = this.input[i] / v;
@ -41,11 +42,12 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
[Benchmark]
public void Simd()
{
Vector<uint> v = new Vector<uint>(this.testValue);
var v = new Vector<uint>(this.testValue);
for (int i = 0; i < this.input.Length; i += Vector<uint>.Count)
{
Vector<uint> a = new Vector<uint>(this.input, i);
var a = new Vector<uint>(this.input, i);
a = a / v;
a.CopyTo(this.result, i);
}

9
tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs

@ -1,10 +1,9 @@
namespace ImageSharp.Benchmarks.General.Vectorization
{
using System;
using System.Numerics;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace ImageSharp.Benchmarks.General.Vectorization
{
public class DivFloat : SIMDBenchmarkBase<float>.Divide
{
protected override float GetTestValue() => 42;

8
tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
public class MulFloat
{
private float[] input;

10
tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
public class MulUInt32
{
private uint[] input;
@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
[Benchmark]
public void Simd()
{
Vector<uint> v = new Vector<uint>(this.testValue);
var v = new Vector<uint>(this.testValue);
for (int i = 0; i < this.input.Length; i += Vector<uint>.Count)
{

6
tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs

@ -1,8 +1,8 @@
using System.Numerics;
using BenchmarkDotNet.Attributes;
namespace ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using BenchmarkDotNet.Attributes;
public class MulUInt32 : SIMDBenchmarkBase<uint>.Multiply
{
protected override uint GetTestValue() => 42u;

12
tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs

@ -1,10 +1,10 @@
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Runtime.InteropServices;
using System.Numerics;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
public class ReinterpretUInt32AsFloat
{
private uint[] input;
@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
[Benchmark(Baseline = true)]
public void Standard()
{
UIntFloatUnion u = default(UIntFloatUnion);
UIntFloatUnion u = default;
for (int i = 0; i < this.input.Length; i++)
{
u.i = this.input[i];

11
tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs

@ -1,10 +1,10 @@
namespace ImageSharp.Benchmarks.General.Vectorization
{
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace ImageSharp.Benchmarks.General.Vectorization
{
public abstract class SIMDBenchmarkBase<T>
where T : struct
{
@ -19,7 +19,6 @@ namespace ImageSharp.Benchmarks.General.Vectorization
protected virtual T GetTestValue() => default(T);
protected virtual Vector<T> GetTestVector() => new Vector<T>(this.GetTestValue());
[Params(32)]
public int InputSize { get; set; }

6
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -16,10 +16,10 @@
<Compile Include="..\ImageSharp.Tests\TestUtilities\TestEnvironment.cs" Link="Tests\TestEnvironment.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.3" />
<PackageReference Include="Colourful" Version="2.0.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
<PackageReference Include="Colourful" Version="2.0.2" />
<PackageReference Include="SixLabors.Shapes.Text" Version="1.0.0-beta0007" />
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ImageSharp.Drawing\ImageSharp.Drawing.csproj" />

13
tests/ImageSharp.Benchmarks/Program.cs

@ -1,15 +1,12 @@
// <copyright file="Program.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Reflection;
using BenchmarkDotNet.Running;
namespace SixLabors.ImageSharp.Benchmarks
{
using BenchmarkDotNet.Running;
using SixLabors.ImageSharp.Formats;
using System.Reflection;
public class Program
{
/// <summary>

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

@ -1,46 +1,40 @@
// <copyright file="Crop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks
{
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Drawing.Drawing2D;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Processing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Processing;
using CoreSize = SixLabors.Primitives.Size;
using CoreSize = SixLabors.Primitives.Size;
namespace SixLabors.ImageSharp.Benchmarks
{
public class Crop : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing Crop")]
public Size CropSystemDrawing()
{
using (Bitmap source = new Bitmap(800, 800))
using (var source = new Bitmap(800, 800))
using (var destination = new Bitmap(100, 100))
using (var graphics = Graphics.FromImage(destination))
{
using (Bitmap destination = new Bitmap(100, 100))
{
using (Graphics graphics = Graphics.FromImage(destination))
{
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(source, new Rectangle(0, 0, 100, 100), 0, 0, 100, 100, GraphicsUnit.Pixel);
}
return destination.Size;
}
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(source, new Rectangle(0, 0, 100, 100), 0, 0, 100, 100, GraphicsUnit.Pixel);
return destination.Size;
}
}
[Benchmark(Description = "ImageSharp Crop")]
public CoreSize CropResizeCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
image.Mutate(x => x.Crop(100, 100));
return new CoreSize(image.Width, image.Height);

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

@ -1,7 +1,5 @@
// <copyright file="DetectEdges.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
@ -53,4 +51,4 @@ namespace SixLabors.ImageSharp.Benchmarks
this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Sobel));
}
}
}
}

13
tests/ImageSharp.Benchmarks/Samplers/Glow.cs

@ -4,7 +4,6 @@
using System;
using System.Buffers;
using System.Numerics;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
@ -35,7 +34,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Glow - Bulk")]
public CoreSize GlowBulk()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
this.bulk.Apply(image, image.Bounds());
return new CoreSize(image.Width, image.Height);
@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp Glow - Parallel")]
public CoreSize GLowSimple()
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
using (var image = new Image<Rgba32>(800, 800))
{
this.parallel.Apply(image, image.Bounds());
return new CoreSize(image.Width, image.Height);
@ -128,7 +127,7 @@ namespace SixLabors.ImageSharp.Benchmarks
int offsetX = x - startX;
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
TPixel packed = default(TPixel);
TPixel packed = default;
packed.FromVector4(
PremultipliedLerp(
sourceColor,
@ -166,9 +165,9 @@ namespace SixLabors.ImageSharp.Benchmarks
// https://en.wikipedia.org/wiki/Alpha_compositing
// Vout = Vs + Vb (1 - Vsa)
// Aout = Vsa + Vsb (1 - Vsa)
Vector3 inverseW = new Vector3(1 - source.W);
Vector3 xyzB = new Vector3(backdrop.X, backdrop.Y, backdrop.Z);
Vector3 xyzS = new Vector3(source.X, source.Y, source.Z);
var inverseW = new Vector3(1 - source.W);
var xyzB = new Vector3(backdrop.X, backdrop.Y, backdrop.Z);
var xyzS = new Vector3(source.X, source.Y, source.Z);
return new Vector4(xyzS + (xyzB * inverseW), source.W + (backdrop.W * (1 - source.W)));
}

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;

5
tests/ImageSharp.Benchmarks/Samplers/Rotate.cs

@ -1,4 +1,7 @@
using BenchmarkDotNet.Attributes;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Primitives;

5
tests/ImageSharp.Benchmarks/Samplers/Skew.cs

@ -1,4 +1,7 @@
using BenchmarkDotNet.Attributes;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Primitives;

5
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs

@ -31,9 +31,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Issues.ExifGetString750Load,
TestImages.Jpeg.Issues.ExifGetString750Transform,
// LibJpeg can open this despite the invalid desity units.
// LibJpeg can open this despite the invalid density units.
TestImages.Jpeg.Issues.Fuzz.ArgumentOutOfRangeException825B,
// LibJpeg can open this despite incorrect colorspace metadata.
TestImages.Jpeg.Issues.IncorrectColorspace855,
// High depth images
TestImages.Jpeg.Baseline.Testorig12bit,
};

168
tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs

@ -0,0 +1,168 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Quantization
{
public class WuQuantizerTests
{
[Fact]
public void SinglePixelOpaque()
{
Configuration config = Configuration.Default;
var quantizer = new WuQuantizer(false);
using (var image = new Image<Rgba32>(config, 1, 1, Rgba32.Black))
using (QuantizedFrame<Rgba32> result = quantizer.CreateFrameQuantizer<Rgba32>(config).QuantizeFrame(image.Frames[0]))
{
Assert.Equal(1, result.Palette.Length);
Assert.Equal(1, result.GetPixelSpan().Length);
Assert.Equal(Rgba32.Black, result.Palette[0]);
Assert.Equal(0, result.GetPixelSpan()[0]);
}
}
[Fact]
public void SinglePixelTransparent()
{
Configuration config = Configuration.Default;
var quantizer = new WuQuantizer(false);
using (var image = new Image<Rgba32>(config, 1, 1, default(Rgba32)))
using (QuantizedFrame<Rgba32> result = quantizer.CreateFrameQuantizer<Rgba32>(config).QuantizeFrame(image.Frames[0]))
{
Assert.Equal(1, result.Palette.Length);
Assert.Equal(1, result.GetPixelSpan().Length);
Assert.Equal(default, result.Palette[0]);
Assert.Equal(0, result.GetPixelSpan()[0]);
}
}
[Fact]
public void GrayScale() => TestScale(c => new Rgba32(c, c, c, 128));
[Fact]
public void RedScale() => TestScale(c => new Rgba32(c, 0, 0, 128));
[Fact]
public void GreenScale() => TestScale(c => new Rgba32(0, c, 0, 128));
[Fact]
public void BlueScale() => TestScale(c => new Rgba32(0, 0, c, 128));
[Fact]
public void AlphaScale() => TestScale(c => new Rgba32(0, 0, 0, c));
[Fact]
public void Palette256()
{
using (var image = new Image<Rgba32>(1, 256))
{
for (int i = 0; i < 256; i++)
{
byte r = (byte)((i % 4) * 85);
byte g = (byte)(((i / 4) % 4) * 85);
byte b = (byte)(((i / 16) % 4) * 85);
byte a = (byte)((i / 64) * 85);
image[0, i] = new Rgba32(r, g, b, a);
}
Configuration config = Configuration.Default;
var quantizer = new WuQuantizer(false);
using (IFrameQuantizer<Rgba32> frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(config))
using (QuantizedFrame<Rgba32> result = frameQuantizer.QuantizeFrame(image.Frames[0]))
{
Assert.Equal(256, result.Palette.Length);
Assert.Equal(256, result.GetPixelSpan().Length);
var actualImage = new Image<Rgba32>(1, 256);
int paletteCount = result.Palette.Length - 1;
for (int y = 0; y < actualImage.Height; y++)
{
Span<Rgba32> row = actualImage.GetPixelRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = result.GetPixelSpan();
int yy = y * actualImage.Width;
for (int x = 0; x < actualImage.Width; x++)
{
int i = x + yy;
row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])];
}
}
Assert.True(image.GetPixelSpan().SequenceEqual(actualImage.GetPixelSpan()));
}
}
}
[Theory]
[WithFile(TestImages.Png.LowColorVariance, PixelTypes.Rgba32)]
public void LowVariance<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
// See https://github.com/SixLabors/ImageSharp/issues/866
using (Image<TPixel> image = provider.GetImage())
{
Configuration config = Configuration.Default;
var quantizer = new WuQuantizer(false);
using (IFrameQuantizer<TPixel> frameQuantizer = quantizer.CreateFrameQuantizer<TPixel>(config))
using (QuantizedFrame<TPixel> result = frameQuantizer.QuantizeFrame(image.Frames[0]))
{
Assert.Equal(48, result.Palette.Length);
}
}
}
private static void TestScale(Func<byte, Rgba32> pixelBuilder)
{
using (var image = new Image<Rgba32>(1, 256))
using (var expectedImage = new Image<Rgba32>(1, 256))
using (var actualImage = new Image<Rgba32>(1, 256))
{
for (int i = 0; i < 256; i++)
{
byte c = (byte)i;
image[0, i] = pixelBuilder.Invoke(c);
}
for (int i = 0; i < 256; i++)
{
byte c = (byte)((i & ~7) + 4);
expectedImage[0, i] = pixelBuilder.Invoke(c);
}
Configuration config = Configuration.Default;
var quantizer = new WuQuantizer(false);
using (IFrameQuantizer<Rgba32> frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(config))
using (QuantizedFrame<Rgba32> result = frameQuantizer.QuantizeFrame(image.Frames[0]))
{
Assert.Equal(4 * 8, result.Palette.Length);
Assert.Equal(256, result.GetPixelSpan().Length);
int paletteCount = result.Palette.Length - 1;
for (int y = 0; y < actualImage.Height; y++)
{
Span<Rgba32> row = actualImage.GetPixelRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = result.GetPixelSpan();
int yy = y * actualImage.Width;
for (int x = 0; x < actualImage.Width; x++)
{
int i = x + yy;
row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])];
}
}
}
Assert.True(expectedImage.GetPixelSpan().SequenceEqual(actualImage.GetPixelSpan()));
}
}
}
}

2
tests/ImageSharp.Tests/TestImages.cs

@ -53,6 +53,7 @@ namespace SixLabors.ImageSharp.Tests
public const string Gray2BitTrans = "Png/gray-2-tRNS.png";
public const string Gray4BitTrans = "Png/gray-4-tRNS.png";
public const string Gray8BitTrans = "Png/gray-8-tRNS.png";
public const string LowColorVariance = "Png/low-variance.png";
// Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html
public const string Filter0 = "Png/filter0.png";
@ -174,6 +175,7 @@ namespace SixLabors.ImageSharp.Tests
public const string ExifGetString750Transform = "Jpg/issues/issue750-exif-tranform.jpg";
public const string ExifGetString750Load = "Jpg/issues/issue750-exif-load.jpg";
public const string IncorrectQuality845 = "Jpg/issues/Issue845-Incorrect-Quality99.jpg";
public const string IncorrectColorspace855 = "Jpg/issues/issue855-incorrect-colorspace.jpg";
public static class Fuzz
{

3
tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fabf628f032dce427a6a0e0f252404d66dc4ce2cd7ee2d7ec72a1fbe79c625d0
size 142656

3
tests/Images/Input/Png/low-variance.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:70c224ef674b546db0ec3281008bb6e2b879e95b0be5625f0af8aff980eee583
size 7844
Loading…
Cancel
Save