Browse Source

Merge pull request #487 from SixLabors/js/non-generic-iquantizer

Use non-generic IQuantizer for image formats
pull/492/head
James Jackson-South 8 years ago
committed by GitHub
parent
commit
bfa854939d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      src/ImageSharp/Common/Helpers/Guard.cs
  2. 15
      src/ImageSharp/Formats/Gif/GifEncoder.cs
  3. 49
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  4. 10
      src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs
  5. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  6. 1
      src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
  7. 10
      src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
  8. 15
      src/ImageSharp/Formats/Png/PngEncoder.cs
  9. 148
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  10. 1
      src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
  11. 2
      src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
  12. 1
      src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs
  13. 1
      src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs
  14. 2
      src/ImageSharp/Primitives/LongRational.cs
  15. 2
      src/ImageSharp/Primitives/Rational.cs
  16. 2
      src/ImageSharp/Primitives/SignedRational.cs
  17. 4
      src/ImageSharp/Processing/Dithering/DiffuseExtensions.cs
  18. 2
      src/ImageSharp/Processing/Dithering/DitherExtensions.cs
  19. 2
      src/ImageSharp/Processing/Dithering/KnownDiffusers.cs
  20. 2
      src/ImageSharp/Processing/Dithering/KnownDitherers.cs
  21. 24
      src/ImageSharp/Processing/Filters/ColorBlindnessExtensions.cs
  22. 2
      src/ImageSharp/Processing/Filters/ColorBlindnessMode.cs
  23. 2
      src/ImageSharp/Processing/Filters/KnownFilterMatrices.cs
  24. 2
      src/ImageSharp/Processing/Filters/Processors/AchromatomalyProcessor.cs
  25. 2
      src/ImageSharp/Processing/Filters/Processors/AchromatopsiaProcessor.cs
  26. 2
      src/ImageSharp/Processing/Filters/Processors/BlackWhiteProcessor.cs
  27. 2
      src/ImageSharp/Processing/Filters/Processors/BrightnessProcessor.cs
  28. 2
      src/ImageSharp/Processing/Filters/Processors/ContrastProcessor.cs
  29. 2
      src/ImageSharp/Processing/Filters/Processors/DeuteranomalyProcessor.cs
  30. 2
      src/ImageSharp/Processing/Filters/Processors/DeuteranopiaProcessor.cs
  31. 2
      src/ImageSharp/Processing/Filters/Processors/GrayscaleBt601Processor.cs
  32. 2
      src/ImageSharp/Processing/Filters/Processors/GrayscaleBt709Processor.cs
  33. 2
      src/ImageSharp/Processing/Filters/Processors/HueProcessor.cs
  34. 2
      src/ImageSharp/Processing/Filters/Processors/InvertProcessor.cs
  35. 2
      src/ImageSharp/Processing/Filters/Processors/KodachromeProcessor.cs
  36. 2
      src/ImageSharp/Processing/Filters/Processors/LomographProcessor.cs
  37. 2
      src/ImageSharp/Processing/Filters/Processors/OpacityProcessor.cs
  38. 2
      src/ImageSharp/Processing/Filters/Processors/PolaroidProcessor.cs
  39. 2
      src/ImageSharp/Processing/Filters/Processors/ProtanomalyProcessor.cs
  40. 2
      src/ImageSharp/Processing/Filters/Processors/ProtanopiaProcessor.cs
  41. 2
      src/ImageSharp/Processing/Filters/Processors/SaturateProcessor.cs
  42. 2
      src/ImageSharp/Processing/Filters/Processors/SepiaProcessor.cs
  43. 2
      src/ImageSharp/Processing/Filters/Processors/TritanomalyProcessor.cs
  44. 2
      src/ImageSharp/Processing/Filters/Processors/TritanopiaProcessor.cs
  45. 56
      src/ImageSharp/Processing/Quantization/Box.cs
  46. 27
      src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs
  47. 35
      src/ImageSharp/Processing/Quantization/FrameQuantizers/IFrameQuantizer{TPixel}.cs
  48. 34
      src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs
  49. 36
      src/ImageSharp/Processing/Quantization/FrameQuantizers/PaletteFrameQuantizer{TPixel}.cs
  50. 76
      src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs
  51. 28
      src/ImageSharp/Processing/Quantization/IQuantizer.cs
  52. 42
      src/ImageSharp/Processing/Quantization/IQuantizer{TPixel}.cs
  53. 29
      src/ImageSharp/Processing/Quantization/KnownQuantizers.cs
  54. 83
      src/ImageSharp/Processing/Quantization/OctreeQuantizer.cs
  55. 65
      src/ImageSharp/Processing/Quantization/PaletteQuantizer.cs
  56. 53
      src/ImageSharp/Processing/Quantization/Processors/QuantizeProcessor.cs
  57. 29
      src/ImageSharp/Processing/Quantization/QuantizationMode.cs
  58. 31
      src/ImageSharp/Processing/Quantization/QuantizeExtensions.cs
  59. 82
      src/ImageSharp/Processing/Quantization/WuQuantizer.cs
  60. 2
      src/ImageSharp/Processing/Transforms/AnchorPositionMode.cs
  61. 6
      src/ImageSharp/Processing/Transforms/FlipExtensions.cs
  62. 2
      src/ImageSharp/Processing/Transforms/FlipMode.cs
  63. 2
      src/ImageSharp/Processing/Transforms/KnownResamplers.cs
  64. 2
      src/ImageSharp/Processing/Transforms/OrientationMode.cs
  65. 2
      src/ImageSharp/Processing/Transforms/PadExtensions.cs
  66. 54
      src/ImageSharp/Processing/Transforms/Processors/AutoOrientProcessor.cs
  67. 16
      src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs
  68. 2
      src/ImageSharp/Processing/Transforms/Processors/RotateProcessor.cs
  69. 2
      src/ImageSharp/Processing/Transforms/Processors/SkewProcessor.cs
  70. 8
      src/ImageSharp/Processing/Transforms/ResizeExtensions.cs
  71. 64
      src/ImageSharp/Processing/Transforms/ResizeHelper.cs
  72. 2
      src/ImageSharp/Processing/Transforms/ResizeMode.cs
  73. 4
      src/ImageSharp/Processing/Transforms/ResizeOptions.cs
  74. 8
      src/ImageSharp/Processing/Transforms/RotateExtensions.cs
  75. 8
      src/ImageSharp/Processing/Transforms/RotateFlipExtensions.cs
  76. 2
      src/ImageSharp/Processing/Transforms/RotateMode.cs
  77. 2
      src/ImageSharp/Processing/Transforms/SkewExtensions.cs
  78. 4
      src/ImageSharp/Processing/Transforms/TransformExtensions.cs
  79. 53
      tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs
  80. 10
      tests/ImageSharp.Benchmarks/Image/EncodePng.cs
  81. 2
      tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
  82. 6
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  83. 64
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  84. 2
      tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs
  85. 2
      tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs
  86. 2
      tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs
  87. 2
      tests/ImageSharp.Tests/Numerics/RationalTests.cs
  88. 2
      tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs
  89. 4
      tests/ImageSharp.Tests/Processing/Binarization/BinaryDitherTest.cs
  90. 4
      tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs
  91. 20
      tests/ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs
  92. 4
      tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs
  93. 30
      tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryDitherTests.cs
  94. 30
      tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs
  95. 22
      tests/ImageSharp.Tests/Processing/Processors/Filters/ColorBlindnessTest.cs
  96. 6
      tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs
  97. 24
      tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs
  98. 12
      tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs
  99. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs
  100. 38
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

10
src/ImageSharp/Common/Helpers/Guard.cs

@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp
{ {
if (value.CompareTo(max) >= 0) if (value.CompareTo(max) >= 0)
{ {
throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than {max}."); throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}.");
} }
} }
@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp
{ {
if (value.CompareTo(max) > 0) if (value.CompareTo(max) > 0)
{ {
throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than or equal to {max}."); throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}.");
} }
} }
@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
parameterName, parameterName,
$"Value must be greater than {min}."); $"Value {value} must be greater than {min}.");
} }
} }
@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp
{ {
if (value.CompareTo(min) < 0) if (value.CompareTo(min) < 0)
{ {
throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min}."); throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}.");
} }
} }
@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp
{ {
if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
{ {
throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min} and less than or equal to {max}."); throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}.");
} }
} }

15
src/ImageSharp/Formats/Gif/GifEncoder.cs

@ -24,20 +24,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding;
/// <summary>
/// Gets or sets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size.
/// </summary>
public int PaletteSize { get; set; } = 0;
/// <summary>
/// Gets or sets the transparency threshold.
/// </summary>
public byte Threshold { get; set; } = 128;
/// <summary> /// <summary>
/// Gets or sets the quantizer for reducing the color count. /// Gets or sets the quantizer for reducing the color count.
/// Defaults to the <see cref="OctreeQuantizer"/>
/// </summary> /// </summary>
public IQuantizer Quantizer { get; set; } public IQuantizer Quantizer { get; set; } = new OctreeQuantizer();
/// <inheritdoc/> /// <inheritdoc/>
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
@ -47,4 +38,4 @@ namespace SixLabors.ImageSharp.Formats.Gif
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
} }
} }

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

@ -25,40 +25,30 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
private readonly byte[] buffer = new byte[16]; private readonly byte[] buffer = new byte[16];
/// <summary>
/// The number of bits requires to store the image palette.
/// </summary>
private int bitDepth;
/// <summary>
/// Whether the current image has multiple frames.
/// </summary>
private bool hasFrames;
/// <summary> /// <summary>
/// Gets the TextEncoding /// Gets the TextEncoding
/// </summary> /// </summary>
private Encoding textEncoding; private readonly Encoding textEncoding;
/// <summary> /// <summary>
/// Gets or sets the quantizer for reducing the color count. /// Gets or sets the quantizer for reducing the color count.
/// </summary> /// </summary>
private IQuantizer quantizer; private readonly IQuantizer quantizer;
/// <summary> /// <summary>
/// Gets or sets the threshold. /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary> /// </summary>
private byte threshold; private readonly bool ignoreMetadata;
/// <summary> /// <summary>
/// Gets or sets the size of the color palette to use. /// The number of bits requires to store the image palette.
/// </summary> /// </summary>
private int paletteSize; private int bitDepth;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// Whether the current image has multiple frames.
/// </summary> /// </summary>
private bool ignoreMetadata; private bool hasFrames;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GifEncoderCore"/> class. /// Initializes a new instance of the <see cref="GifEncoderCore"/> class.
@ -69,10 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{ {
this.memoryManager = memoryManager; this.memoryManager = memoryManager;
this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding;
this.quantizer = options.Quantizer; this.quantizer = options.Quantizer;
this.threshold = options.Threshold;
this.paletteSize = options.PaletteSize;
this.ignoreMetadata = options.IgnoreMetadata; this.ignoreMetadata = options.IgnoreMetadata;
} }
@ -88,24 +75,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
this.quantizer = this.quantizer ?? new OctreeQuantizer<TPixel>();
// Do not use IDisposable pattern here as we want to preserve the stream. // Do not use IDisposable pattern here as we want to preserve the stream.
var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Ensure that pallete size can be set but has a fallback.
int size = this.paletteSize;
size = size > 0 ? size.Clamp(1, 256) : 256;
// Get the number of bits.
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(size);
this.hasFrames = image.Frames.Count > 1; this.hasFrames = image.Frames.Count > 1;
var pixelQuantizer = (IQuantizer<TPixel>)this.quantizer;
// Quantize the image returning a palette. // Quantize the image returning a palette.
QuantizedFrame<TPixel> quantized = pixelQuantizer.Quantize(image.Frames.RootFrame, size); QuantizedFrame<TPixel> quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(image.Frames.RootFrame);
// Get the number of bits.
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
int index = this.GetTransparentIndex(quantized); int index = this.GetTransparentIndex(quantized);
@ -128,7 +107,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{ {
if (quantized == null) if (quantized == null)
{ {
quantized = pixelQuantizer.Quantize(frame, size); quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
} }
this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantized)); this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantized));
@ -136,7 +115,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.WriteColorTable(quantized, writer); this.WriteColorTable(quantized, writer);
this.WriteImageData(quantized, writer); this.WriteImageData(quantized, writer);
quantized = null; // so next frame can regenerate it quantized = null; // So next frame can regenerate it
} }
// TODO: Write extension etc // TODO: Write extension etc

10
src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs

@ -21,16 +21,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
Encoding TextEncoding { get; } Encoding TextEncoding { get; }
/// <summary>
/// Gets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size.
/// </summary>
int PaletteSize { get; }
/// <summary>
/// Gets the transparency threshold.
/// </summary>
byte Threshold { get; }
/// <summary> /// <summary>
/// Gets the quantizer for reducing the color count. /// Gets the quantizer for reducing the color count.
/// </summary> /// </summary>

2
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -3,7 +3,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
@ -11,6 +10,7 @@ using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc; using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort

1
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

@ -12,6 +12,7 @@ using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc; using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
{ {

10
src/ImageSharp/Formats/Png/IPngEncoderOptions.cs

@ -10,16 +10,6 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
internal interface IPngEncoderOptions internal interface IPngEncoderOptions
{ {
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being encoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the size of the color palette to use. Set to zero to leav png encoding to use pixel data.
/// </summary>
int PaletteSize { get; }
/// <summary> /// <summary>
/// Gets the png color type /// Gets the png color type
/// </summary> /// </summary>

15
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -13,16 +13,6 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions
{ {
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded.
/// </summary>
public bool IgnoreMetadata { get; set; }
/// <summary>
/// Gets or sets the size of the color palette to use. Set to zero to leave png encoding to use pixel data.
/// </summary>
public int PaletteSize { get; set; } = 0;
/// <summary> /// <summary>
/// Gets or sets the png color type /// Gets or sets the png color type
/// </summary> /// </summary>
@ -44,8 +34,9 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Gets or sets quantizer for reducing the color count. /// Gets or sets quantizer for reducing the color count.
/// Defaults to the <see cref="WuQuantizer"/>
/// </summary> /// </summary>
public IQuantizer Quantizer { get; set; } public IQuantizer Quantizer { get; set; } = new WuQuantizer();
/// <summary> /// <summary>
/// Gets or sets the transparency threshold. /// Gets or sets the transparency threshold.
@ -73,4 +64,4 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
} }
} }
} }

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

@ -40,6 +40,36 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
private readonly Crc32 crc = new Crc32(); private readonly Crc32 crc = new Crc32();
/// <summary>
/// The png color type.
/// </summary>
private readonly PngColorType pngColorType;
/// <summary>
/// The quantizer for reducing the color count.
/// </summary>
private readonly IQuantizer quantizer;
/// <summary>
/// Gets or sets the CompressionLevel value
/// </summary>
private readonly int compressionLevel;
/// <summary>
/// Gets or sets the Gamma value
/// </summary>
private readonly float gamma;
/// <summary>
/// Gets or sets the Threshold value
/// </summary>
private readonly byte threshold;
/// <summary>
/// Gets or sets a value indicating whether to Write Gamma
/// </summary>
private readonly bool writeGamma;
/// <summary> /// <summary>
/// Contains the raw pixel data from an indexed image. /// Contains the raw pixel data from an indexed image.
/// </summary> /// </summary>
@ -101,50 +131,10 @@ namespace SixLabors.ImageSharp.Formats.Png
private IManagedByteBuffer average; private IManagedByteBuffer average;
/// <summary> /// <summary>
/// The buffer for the paeth filter /// The buffer for the Paeth filter
/// </summary> /// </summary>
private IManagedByteBuffer paeth; private IManagedByteBuffer paeth;
/// <summary>
/// The png color type.
/// </summary>
private PngColorType pngColorType;
/// <summary>
/// The quantizer for reducing the color count.
/// </summary>
private IQuantizer quantizer;
/// <summary>
/// Gets or sets a value indicating whether to ignore metadata
/// </summary>
private bool ignoreMetadata;
/// <summary>
/// Gets or sets the Quality value
/// </summary>
private int paletteSize;
/// <summary>
/// Gets or sets the CompressionLevel value
/// </summary>
private int compressionLevel;
/// <summary>
/// Gets or sets the Gamma value
/// </summary>
private float gamma;
/// <summary>
/// Gets or sets the Threshold value
/// </summary>
private byte threshold;
/// <summary>
/// Gets or sets a value indicating whether to Write Gamma
/// </summary>
private bool writeGamma;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class. /// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary> /// </summary>
@ -153,8 +143,6 @@ namespace SixLabors.ImageSharp.Formats.Png
public PngEncoderCore(MemoryManager memoryManager, IPngEncoderOptions options) public PngEncoderCore(MemoryManager memoryManager, IPngEncoderOptions options)
{ {
this.memoryManager = memoryManager; this.memoryManager = memoryManager;
this.ignoreMetadata = options.IgnoreMetadata;
this.paletteSize = options.PaletteSize > 0 ? options.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue;
this.pngColorType = options.PngColorType; this.pngColorType = options.PngColorType;
this.compressionLevel = options.CompressionLevel; this.compressionLevel = options.CompressionLevel;
this.gamma = options.Gamma; this.gamma = options.Gamma;
@ -190,28 +178,27 @@ namespace SixLabors.ImageSharp.Formats.Png
stream.Write(this.chunkDataBuffer, 0, 8); stream.Write(this.chunkDataBuffer, 0, 8);
// Set correct color type if the color count is 256 or less. QuantizedFrame<TPixel> quantized = null;
if (this.paletteSize <= 256) if (this.pngColorType == PngColorType.Palette)
{
this.pngColorType = PngColorType.Palette;
}
if (this.pngColorType == PngColorType.Palette && this.paletteSize > 256)
{ {
this.paletteSize = 256; // Create quantized frame returning the palette and set the bit depth.
} quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(image.Frames.RootFrame);
this.palettePixelData = quantized.Pixels;
byte bits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
// Set correct bit depth. // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk
this.bitDepth = this.paletteSize <= 256 if (bits == 3)
? (byte)ImageMaths.GetBitsNeededForColorDepth(this.paletteSize).Clamp(1, 8) {
: (byte)8; bits = 4;
}
else if (bits >= 5 || bits <= 7)
{
bits = 8;
}
// Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk this.bitDepth = bits;
if (this.bitDepth == 3)
{
this.bitDepth = 4;
} }
else if (this.bitDepth >= 5 || this.bitDepth <= 7) else
{ {
this.bitDepth = 8; this.bitDepth = 8;
} }
@ -232,9 +219,9 @@ namespace SixLabors.ImageSharp.Formats.Png
this.WriteHeaderChunk(stream, header); this.WriteHeaderChunk(stream, header);
// Collect the indexed pixel data // Collect the indexed pixel data
if (this.pngColorType == PngColorType.Palette) if (quantized != null)
{ {
this.CollectIndexedBytes(image.Frames.RootFrame, stream, header); this.WritePaletteChunk(stream, header, quantized);
} }
this.WritePhysicalChunk(stream, image); this.WritePhysicalChunk(stream, image);
@ -296,21 +283,6 @@ namespace SixLabors.ImageSharp.Formats.Png
stream.Write(buffer, 0, 4); stream.Write(buffer, 0, 4);
} }
/// <summary>
/// Collects the indexed pixel data.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The image to encode.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="header">The <see cref="PngHeader"/>.</param>
private void CollectIndexedBytes<TPixel>(ImageFrame<TPixel> image, Stream stream, PngHeader header)
where TPixel : struct, IPixel<TPixel>
{
// Quantize the image and get the pixels.
QuantizedFrame<TPixel> quantized = this.WritePaletteChunk(stream, header, image);
this.palettePixelData = quantized.Pixels;
}
/// <summary> /// <summary>
/// Collects a row of grayscale pixels. /// Collects a row of grayscale pixels.
/// </summary> /// </summary>
@ -496,24 +468,10 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="header">The <see cref="PngHeader"/>.</param> /// <param name="header">The <see cref="PngHeader"/>.</param>
/// <param name="image">The image to encode.</param> /// <param name="quantized">The quantized frame.</param>
/// <returns>The <see cref="QuantizedFrame{TPixel}"/></returns> private void WritePaletteChunk<TPixel>(Stream stream, PngHeader header, QuantizedFrame<TPixel> quantized)
private QuantizedFrame<TPixel> WritePaletteChunk<TPixel>(Stream stream, PngHeader header, ImageFrame<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.paletteSize > 256)
{
return null;
}
if (this.quantizer == null)
{
this.quantizer = new WuQuantizer<TPixel>();
}
// Quantize the image returning a palette. This boxing is icky.
QuantizedFrame<TPixel> quantized = ((IQuantizer<TPixel>)this.quantizer).Quantize(image, this.paletteSize);
// Grab the palette and write it to the stream. // Grab the palette and write it to the stream.
TPixel[] palette = quantized.Palette; TPixel[] palette = quantized.Palette;
byte pixelCount = palette.Length.ToByte(); byte pixelCount = palette.Length.ToByte();
@ -560,8 +518,6 @@ namespace SixLabors.ImageSharp.Formats.Png
this.WriteChunk(stream, PngChunkTypes.PaletteAlpha, alphaTable.Array, 0, pixelCount); this.WriteChunk(stream, PngChunkTypes.PaletteAlpha, alphaTable.Array, 0, pixelCount);
} }
} }
return quantized;
} }
/// <summary> /// <summary>

1
src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO; using System.IO;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {

2
src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs

@ -1,10 +1,12 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {

1
src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {

1
src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {

2
src/ImageSharp/MetaData/Profiles/Exif/LongRational.cs → src/ImageSharp/Primitives/LongRational.cs

@ -5,7 +5,7 @@ using System;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.Primitives
{ {
/// <summary> /// <summary>
/// Represents a number that can be expressed as a fraction /// Represents a number that can be expressed as a fraction

2
src/ImageSharp/MetaData/Profiles/Exif/Rational.cs → src/ImageSharp/Primitives/Rational.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.Primitives
{ {
/// <summary> /// <summary>
/// Represents a number that can be expressed as a fraction. /// Represents a number that can be expressed as a fraction.

2
src/ImageSharp/MetaData/Profiles/Exif/SignedRational.cs → src/ImageSharp/Primitives/SignedRational.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif namespace SixLabors.ImageSharp.Primitives
{ {
/// <summary> /// <summary>
/// Represents a number that can be expressed as a fraction. /// Represents a number that can be expressed as a fraction.

4
src/ImageSharp/Processing/Dithering/DiffuseExtensions.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source) public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Diffuse(source, DiffuseMode.FloydSteinberg, .5F); => Diffuse(source, KnownDiffusers.FloydSteinberg, .5F);
/// <summary> /// <summary>
/// Dithers the image reducing it to a web-safe palette using error diffusion. /// Dithers the image reducing it to a web-safe palette using error diffusion.
@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, float threshold) public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Diffuse(source, DiffuseMode.FloydSteinberg, threshold); => Diffuse(source, KnownDiffusers.FloydSteinberg, threshold);
/// <summary> /// <summary>
/// Dithers the image reducing it to a web-safe palette using error diffusion. /// Dithers the image reducing it to a web-safe palette using error diffusion.

2
src/ImageSharp/Processing/Dithering/DitherExtensions.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source) public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Dither(source, DitherMode.BayerDither4x4); => Dither(source, KnownDitherers.BayerDither4x4);
/// <summary> /// <summary>
/// Dithers the image reducing it to a web-safe palette using ordered dithering. /// Dithers the image reducing it to a web-safe palette using ordered dithering.

2
src/ImageSharp/Processing/Dithering/DiffuseMode.cs → src/ImageSharp/Processing/Dithering/KnownDiffusers.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <summary> /// <summary>
/// Contains reusable static instances of known error diffusion algorithms /// Contains reusable static instances of known error diffusion algorithms
/// </summary> /// </summary>
public static class DiffuseMode public static class KnownDiffusers
{ {
/// <summary> /// <summary>
/// Gets the error diffuser that implements the Atkinson algorithm. /// Gets the error diffuser that implements the Atkinson algorithm.

2
src/ImageSharp/Processing/Dithering/DitherMode.cs → src/ImageSharp/Processing/Dithering/KnownDitherers.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <summary> /// <summary>
/// Contains reusable static instances of known ordered dither matrices /// Contains reusable static instances of known ordered dither matrices
/// </summary> /// </summary>
public class DitherMode public class KnownDitherers
{ {
/// <summary> /// <summary>
/// Gets the order ditherer using the 2x2 Bayer dithering matrix /// Gets the order ditherer using the 2x2 Bayer dithering matrix

24
src/ImageSharp/Processing/Filters/ColorBlindnessExtensions.cs

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing.Filters
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param> /// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindness colorBlindness) public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindnessMode colorBlindness)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(GetProcessor<TPixel>(colorBlindness)); => source.ApplyProcessor(GetProcessor<TPixel>(colorBlindness));
@ -29,33 +29,33 @@ namespace SixLabors.ImageSharp.Processing.Filters
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param> /// <param name="colorBlindnessMode">The type of color blindness simulator to apply.</param>
/// <param name="rectangle"> /// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param> /// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindness colorBlindness, Rectangle rectangle) public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindnessMode colorBlindnessMode, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(GetProcessor<TPixel>(colorBlindness), rectangle); => source.ApplyProcessor(GetProcessor<TPixel>(colorBlindnessMode), rectangle);
private static IImageProcessor<TPixel> GetProcessor<TPixel>(ColorBlindness colorBlindness) private static IImageProcessor<TPixel> GetProcessor<TPixel>(ColorBlindnessMode colorBlindness)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
switch (colorBlindness) switch (colorBlindness)
{ {
case Filters.ColorBlindness.Achromatomaly: case ColorBlindnessMode.Achromatomaly:
return new AchromatomalyProcessor<TPixel>(); return new AchromatomalyProcessor<TPixel>();
case Filters.ColorBlindness.Achromatopsia: case ColorBlindnessMode.Achromatopsia:
return new AchromatopsiaProcessor<TPixel>(); return new AchromatopsiaProcessor<TPixel>();
case Filters.ColorBlindness.Deuteranomaly: case ColorBlindnessMode.Deuteranomaly:
return new DeuteranomalyProcessor<TPixel>(); return new DeuteranomalyProcessor<TPixel>();
case Filters.ColorBlindness.Deuteranopia: case ColorBlindnessMode.Deuteranopia:
return new DeuteranopiaProcessor<TPixel>(); return new DeuteranopiaProcessor<TPixel>();
case Filters.ColorBlindness.Protanomaly: case ColorBlindnessMode.Protanomaly:
return new ProtanomalyProcessor<TPixel>(); return new ProtanomalyProcessor<TPixel>();
case Filters.ColorBlindness.Protanopia: case ColorBlindnessMode.Protanopia:
return new ProtanopiaProcessor<TPixel>(); return new ProtanopiaProcessor<TPixel>();
case Filters.ColorBlindness.Tritanomaly: case ColorBlindnessMode.Tritanomaly:
return new TritanomalyProcessor<TPixel>(); return new TritanomalyProcessor<TPixel>();
default: default:
return new TritanopiaProcessor<TPixel>(); return new TritanopiaProcessor<TPixel>();

2
src/ImageSharp/Processing/Filters/ColorBlindness.cs → src/ImageSharp/Processing/Filters/ColorBlindnessMode.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Filters
/// <summary> /// <summary>
/// Enumerates the various types of defined color blindness filters. /// Enumerates the various types of defined color blindness filters.
/// </summary> /// </summary>
public enum ColorBlindness public enum ColorBlindnessMode
{ {
/// <summary> /// <summary>
/// Partial color desensitivity. /// Partial color desensitivity.

2
src/ImageSharp/Processing/Filters/MatrixFilters.cs → src/ImageSharp/Processing/Filters/KnownFilterMatrices.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing.Filters
/// <summary> /// <summary>
/// A collection of known <see cref="Matrix4x4"/> values for composing filters /// A collection of known <see cref="Matrix4x4"/> values for composing filters
/// </summary> /// </summary>
public static class MatrixFilters public static class KnownFilterMatrices
{ {
/// <summary> /// <summary>
/// Gets a filter recreating Achromatomaly (Color desensitivity) color blindness /// Gets a filter recreating Achromatomaly (Color desensitivity) color blindness

2
src/ImageSharp/Processing/Filters/Processors/AchromatomalyProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="AchromatomalyProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="AchromatomalyProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public AchromatomalyProcessor() public AchromatomalyProcessor()
: base(MatrixFilters.AchromatomalyFilter) : base(KnownFilterMatrices.AchromatomalyFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/AchromatopsiaProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="AchromatopsiaProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="AchromatopsiaProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public AchromatopsiaProcessor() public AchromatopsiaProcessor()
: base(MatrixFilters.AchromatopsiaFilter) : base(KnownFilterMatrices.AchromatopsiaFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/BlackWhiteProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="BlackWhiteProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="BlackWhiteProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public BlackWhiteProcessor() public BlackWhiteProcessor()
: base(MatrixFilters.BlackWhiteFilter) : base(KnownFilterMatrices.BlackWhiteFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/BrightnessProcessor.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </remarks> /// </remarks>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param> /// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
public BrightnessProcessor(float amount) public BrightnessProcessor(float amount)
: base(MatrixFilters.CreateBrightnessFilter(amount)) : base(KnownFilterMatrices.CreateBrightnessFilter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/ContrastProcessor.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </remarks> /// </remarks>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param> /// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
public ContrastProcessor(float amount) public ContrastProcessor(float amount)
: base(MatrixFilters.CreateContrastFilter(amount)) : base(KnownFilterMatrices.CreateContrastFilter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/DeuteranomalyProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="DeuteranomalyProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="DeuteranomalyProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public DeuteranomalyProcessor() public DeuteranomalyProcessor()
: base(MatrixFilters.DeuteranomalyFilter) : base(KnownFilterMatrices.DeuteranomalyFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/DeuteranopiaProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="DeuteranopiaProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="DeuteranopiaProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public DeuteranopiaProcessor() public DeuteranopiaProcessor()
: base(MatrixFilters.DeuteranopiaFilter) : base(KnownFilterMatrices.DeuteranopiaFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/GrayscaleBt601Processor.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </summary> /// </summary>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param> /// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
public GrayscaleBt601Processor(float amount) public GrayscaleBt601Processor(float amount)
: base(MatrixFilters.CreateGrayscaleBt601Filter(amount)) : base(KnownFilterMatrices.CreateGrayscaleBt601Filter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/GrayscaleBt709Processor.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </summary> /// </summary>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param> /// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
public GrayscaleBt709Processor(float amount) public GrayscaleBt709Processor(float amount)
: base(MatrixFilters.CreateGrayscaleBt709Filter(amount)) : base(KnownFilterMatrices.CreateGrayscaleBt709Filter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/HueProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </summary> /// </summary>
/// <param name="degrees">The angle of rotation in degrees</param> /// <param name="degrees">The angle of rotation in degrees</param>
public HueProcessor(float degrees) public HueProcessor(float degrees)
: base(MatrixFilters.CreateHueFilter(degrees)) : base(KnownFilterMatrices.CreateHueFilter(degrees))
{ {
this.Degrees = degrees; this.Degrees = degrees;
} }

2
src/ImageSharp/Processing/Filters/Processors/InvertProcessor.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </summary> /// </summary>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param> /// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
public InvertProcessor(float amount) public InvertProcessor(float amount)
: base(MatrixFilters.CreateInvertFilter(amount)) : base(KnownFilterMatrices.CreateInvertFilter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/KodachromeProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="KodachromeProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="KodachromeProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public KodachromeProcessor() public KodachromeProcessor()
: base(MatrixFilters.KodachromeFilter) : base(KnownFilterMatrices.KodachromeFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/LomographProcessor.cs

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="LomographProcessor{TPixel}" /> class. /// Initializes a new instance of the <see cref="LomographProcessor{TPixel}" /> class.
/// </summary> /// </summary>
public LomographProcessor() public LomographProcessor()
: base(MatrixFilters.LomographFilter) : base(KnownFilterMatrices.LomographFilter)
{ {
} }

2
src/ImageSharp/Processing/Filters/Processors/OpacityProcessor.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </summary> /// </summary>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param> /// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
public OpacityProcessor(float amount) public OpacityProcessor(float amount)
: base(MatrixFilters.CreateOpacityFilter(amount)) : base(KnownFilterMatrices.CreateOpacityFilter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/PolaroidProcessor.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="PolaroidProcessor{TPixel}" /> class. /// Initializes a new instance of the <see cref="PolaroidProcessor{TPixel}" /> class.
/// </summary> /// </summary>
public PolaroidProcessor() public PolaroidProcessor()
: base(MatrixFilters.PolaroidFilter) : base(KnownFilterMatrices.PolaroidFilter)
{ {
} }

2
src/ImageSharp/Processing/Filters/Processors/ProtanomalyProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="ProtanomalyProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="ProtanomalyProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public ProtanomalyProcessor() public ProtanomalyProcessor()
: base(MatrixFilters.ProtanomalyFilter) : base(KnownFilterMatrices.ProtanomalyFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/ProtanopiaProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="ProtanopiaProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="ProtanopiaProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public ProtanopiaProcessor() public ProtanopiaProcessor()
: base(MatrixFilters.ProtanopiaFilter) : base(KnownFilterMatrices.ProtanopiaFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/SaturateProcessor.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </remarks> /// </remarks>
/// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param> /// <param name="amount">The proportion of the conversion. Must be greater than or equal to 0.</param>
public SaturateProcessor(float amount) public SaturateProcessor(float amount)
: base(MatrixFilters.CreateSaturateFilter(amount)) : base(KnownFilterMatrices.CreateSaturateFilter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/SepiaProcessor.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// </summary> /// </summary>
/// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param> /// <param name="amount">The proportion of the conversion. Must be between 0 and 1.</param>
public SepiaProcessor(float amount) public SepiaProcessor(float amount)
: base(MatrixFilters.CreateSepiaFilter(amount)) : base(KnownFilterMatrices.CreateSepiaFilter(amount))
{ {
this.Amount = amount; this.Amount = amount;
} }

2
src/ImageSharp/Processing/Filters/Processors/TritanomalyProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="TritanomalyProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="TritanomalyProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public TritanomalyProcessor() public TritanomalyProcessor()
: base(MatrixFilters.TritanomalyFilter) : base(KnownFilterMatrices.TritanomalyFilter)
{ {
} }
} }

2
src/ImageSharp/Processing/Filters/Processors/TritanopiaProcessor.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Filters.Processors
/// Initializes a new instance of the <see cref="TritanopiaProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="TritanopiaProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public TritanopiaProcessor() public TritanopiaProcessor()
: base(MatrixFilters.TritanopiaFilter) : base(KnownFilterMatrices.TritanopiaFilter)
{ {
} }
} }

56
src/ImageSharp/Processing/Quantization/Box.cs

@ -1,56 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Represents a box color cube.
/// </summary>
internal struct Box
{
/// <summary>
/// Gets or sets the min red value, exclusive.
/// </summary>
public int R0 { get; set; }
/// <summary>
/// Gets or sets the max red value, inclusive.
/// </summary>
public int R1 { get; set; }
/// <summary>
/// Gets or sets the min green value, exclusive.
/// </summary>
public int G0 { get; set; }
/// <summary>
/// Gets or sets the max green value, inclusive.
/// </summary>
public int G1 { get; set; }
/// <summary>
/// Gets or sets the min blue value, exclusive.
/// </summary>
public int B0 { get; set; }
/// <summary>
/// Gets or sets the max blue value, inclusive.
/// </summary>
public int B1 { get; set; }
/// <summary>
/// Gets or sets the min alpha value, exclusive.
/// </summary>
public int A0 { get; set; }
/// <summary>
/// Gets or sets the max alpha value, inclusive.
/// </summary>
public int A1 { get; set; }
/// <summary>
/// Gets or sets the volume.
/// </summary>
public int Volume { get; set; }
}
}

27
src/ImageSharp/Processing/Quantization/QuantizerBase{TPixel}.cs → src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs

@ -6,16 +6,15 @@ using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion; using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
namespace SixLabors.ImageSharp.Processing.Quantization namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{ {
/// <summary> /// <summary>
/// Encapsulates methods to calculate the color palette of an image. /// The base class for all <see cref="IFrameQuantizer{TPixel}"/> implementations
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public abstract class QuantizerBase<TPixel> : IQuantizer<TPixel> public abstract class FrameQuantizerBase<TPixel> : IFrameQuantizer<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
@ -24,29 +23,35 @@ namespace SixLabors.ImageSharp.Processing.Quantization
private readonly bool singlePass; private readonly bool singlePass;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="QuantizerBase{TPixel}"/> class. /// Initializes a new instance of the <see cref="FrameQuantizerBase{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="quantizer">The quantizer</param>
/// <param name="singlePass"> /// <param name="singlePass">
/// If true, the quantization only needs to loop through the source pixels once /// If true, the quantization process only needs to loop through the source pixels once
/// </param> /// </param>
/// <remarks> /// <remarks>
/// If you construct this class with a true value for singlePass, then the code will, when quantizing your image, /// If you construct this class with a true value for singlePass, then the code will, when quantizing your image,
/// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage' /// only call the <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/> methods.
/// If two passes are required, the code will also call <see cref="SecondPass(ImageFrame{TPixel}, byte[], int, int)"/>
/// and then 'QuantizeImage'. /// and then 'QuantizeImage'.
/// </remarks> /// </remarks>
protected QuantizerBase(bool singlePass) protected FrameQuantizerBase(IQuantizer quantizer, bool singlePass)
{ {
Guard.NotNull(quantizer, nameof(quantizer));
this.Diffuser = quantizer.Diffuser;
this.Dither = this.Diffuser != null;
this.singlePass = singlePass; this.singlePass = singlePass;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Dither { get; set; } = true; public bool Dither { get; }
/// <inheritdoc /> /// <inheritdoc />
public IErrorDiffuser DitherType { get; set; } = DiffuseMode.FloydSteinberg; public IErrorDiffuser Diffuser { get; }
/// <inheritdoc/> /// <inheritdoc/>
public virtual QuantizedFrame<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors) public virtual QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
{ {
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));

35
src/ImageSharp/Processing/Quantization/FrameQuantizers/IFrameQuantizer{TPixel}.cs

@ -0,0 +1,35 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{
/// <summary>
/// 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>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets a value indicating whether to apply dithering to the output image.
/// </summary>
bool Dither { get; }
/// <summary>
/// Gets the error diffusion algorithm to apply to the output image.
/// </summary>
IErrorDiffuser Diffuser { get; }
/// <summary>
/// Quantize an image frame and return the resulting output pixels.
/// </summary>
/// <param name="image">The image to quantize.</param>
/// <returns>
/// A <see cref="QuantizedFrame{TPixel}"/> representing a quantized version of the image pixels.
/// </returns>
QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image);
}
}

34
src/ImageSharp/Processing/Quantization/OctreeQuantizer{TPixel}.cs → src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs

@ -8,14 +8,14 @@ using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Quantization namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{ {
/// <summary> /// <summary>
/// Encapsulates methods to calculate the color palette if an image using an Octree pattern. /// Encapsulates methods to calculate the color palette if an image using an Octree pattern.
/// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/> /// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/>
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed class OctreeQuantizer<TPixel> : QuantizerBase<TPixel> internal sealed class OctreeFrameQuantizer<TPixel> : FrameQuantizerBase<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
@ -24,14 +24,14 @@ namespace SixLabors.ImageSharp.Processing.Quantization
private readonly Dictionary<TPixel, byte> colorMap = new Dictionary<TPixel, byte>(); private readonly Dictionary<TPixel, byte> colorMap = new Dictionary<TPixel, byte>();
/// <summary> /// <summary>
/// Stores the tree /// Maximum allowed color depth
/// </summary> /// </summary>
private Octree octree; private readonly byte colors;
/// <summary> /// <summary>
/// Maximum allowed color depth /// Stores the tree
/// </summary> /// </summary>
private byte colors; private readonly Octree octree;
/// <summary> /// <summary>
/// The reduced image palette /// The reduced image palette
@ -44,26 +44,18 @@ namespace SixLabors.ImageSharp.Processing.Quantization
private byte transparentIndex; private byte transparentIndex;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="OctreeQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="OctreeFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="quantizer">The octree quantizer</param>
/// <remarks> /// <remarks>
/// The Octree quantizer is a two pass algorithm. The initial pass sets up the Octree, /// The Octree quantizer is a two pass algorithm. The initial pass sets up the Octree,
/// the second pass quantizes a color based on the nodes in the tree /// the second pass quantizes a color based on the nodes in the tree
/// </remarks> /// </remarks>
public OctreeQuantizer() public OctreeFrameQuantizer(OctreeQuantizer quantizer)
: base(false) : base(quantizer, false)
{ {
} this.colors = (byte)quantizer.MaxColors;
/// <inheritdoc/>
public override QuantizedFrame<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors)
{
this.colors = (byte)maxColors.Clamp(1, 255);
this.octree = new Octree(this.GetBitsNeededForColorDepth(this.colors)); this.octree = new Octree(this.GetBitsNeededForColorDepth(this.colors));
this.palette = null;
this.colorMap.Clear();
return base.Quantize(image, this.colors);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -129,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization
if (this.Dither) if (this.Dither)
{ {
// Apply the dithering matrix. We have to reapply the value now as the original has changed. // Apply the dithering matrix. We have to reapply the value now as the original has changed.
this.DitherType.Dither(source, sourcePixel, transformedPixel, x, y, 0, 0, width, height); this.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, 0, 0, width, height);
} }
output[(y * source.Width) + x] = pixelValue; output[(y * source.Width) + x] = pixelValue;
@ -322,7 +314,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization
} }
// Now palletize the nodes // Now palletize the nodes
TPixel[] palette = new TPixel[colorCount + 1]; var palette = new TPixel[colorCount + 1];
int paletteIndex = 0; int paletteIndex = 0;
this.root.ConstructPalette(palette, ref paletteIndex); this.root.ConstructPalette(palette, ref paletteIndex);

36
src/ImageSharp/Processing/Quantization/PaletteQuantizer{TPixel}.cs → src/ImageSharp/Processing/Quantization/FrameQuantizers/PaletteFrameQuantizer{TPixel}.cs

@ -7,15 +7,14 @@ using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Quantization namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{ {
/// <summary> /// <summary>
/// Encapsulates methods to create a quantized image based upon the given palette. /// Encapsulates methods to create a quantized image based upon the given palette.
/// If no palette is given this will default to the web safe colors defined in the CSS Color Module Level 4.
/// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/> /// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/>
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed class PaletteQuantizer<TPixel> : QuantizerBase<TPixel> internal sealed class PaletteFrameQuantizer<TPixel> : FrameQuantizerBase<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
@ -26,33 +25,16 @@ namespace SixLabors.ImageSharp.Processing.Quantization
/// <summary> /// <summary>
/// List of all colors in the palette /// List of all colors in the palette
/// </summary> /// </summary>
private TPixel[] colors; private readonly TPixel[] colors;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="PaletteFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
public PaletteQuantizer() /// <param name="quantizer">The palette quantizer</param>
: this(NamedColors<TPixel>.WebSafePalette) public PaletteFrameQuantizer(PaletteQuantizer quantizer)
: base(quantizer, true)
{ {
} this.colors = quantizer.GetPalette<TPixel>();
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="palette">The palette to select substitute colors from.</param>
public PaletteQuantizer(TPixel[] palette = null)
: base(true)
{
Guard.NotNull(palette, nameof(palette));
this.colors = palette;
}
/// <inheritdoc/>
public override QuantizedFrame<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors)
{
Array.Resize(ref this.colors, maxColors.Clamp(1, 255));
this.colorMap.Clear();
return base.Quantize(image, maxColors);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -95,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization
if (this.Dither) if (this.Dither)
{ {
// Apply the dithering matrix. We have to reapply the value now as the original has changed. // Apply the dithering matrix. We have to reapply the value now as the original has changed.
this.DitherType.Dither(source, sourcePixel, transformedPixel, x, y, 0, 0, width, height); this.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, 0, 0, width, height);
} }
output[(y * source.Width) + x] = pixelValue; output[(y * source.Width) + x] = pixelValue;

76
src/ImageSharp/Processing/Quantization/WuQuantizer{TPixel}.cs → src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs

@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Quantization namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{ {
/// <summary> /// <summary>
/// An implementation of Wu's color quantizer with alpha channel. /// An implementation of Wu's color quantizer with alpha channel.
@ -32,10 +32,10 @@ namespace SixLabors.ImageSharp.Processing.Quantization
/// </para> /// </para>
/// </remarks> /// </remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public class WuQuantizer<TPixel> : QuantizerBase<TPixel> internal sealed class WuFrameQuantizer<TPixel> : FrameQuantizerBase<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// TODO: The WuQuantizer<TPixel> code is rising several questions: // 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 ) // - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes )
// - Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case? // - 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! // (T, R, G, B, A, M2) could be grouped together!
@ -124,26 +124,23 @@ namespace SixLabors.ImageSharp.Processing.Quantization
private Box[] colorCube; private Box[] colorCube;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WuQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="WuFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="quantizer">The wu quantizer</param>
/// <remarks> /// <remarks>
/// The Wu quantizer is a two pass algorithm. The initial pass sets up the 3-D color histogram, /// The Wu quantizer is a two pass algorithm. The initial pass sets up the 3-D color histogram,
/// the second pass quantizes a color based on the position in the histogram. /// the second pass quantizes a color based on the position in the histogram.
/// </remarks> /// </remarks>
public WuQuantizer() public WuFrameQuantizer(WuQuantizer quantizer)
: base(false) : base(quantizer, false)
{ {
this.colors = quantizer.MaxColors;
} }
/// <inheritdoc/> /// <inheritdoc/>
public override QuantizedFrame<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors) public override QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
{ {
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
this.colors = maxColors.Clamp(1, 255);
this.palette = null;
this.colorMap.Clear();
MemoryManager memoryManager = image.MemoryManager; MemoryManager memoryManager = image.MemoryManager;
try try
@ -156,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization
this.m2 = memoryManager.AllocateClean<float>(TableLength); this.m2 = memoryManager.AllocateClean<float>(TableLength);
this.tag = memoryManager.AllocateClean<byte>(TableLength); this.tag = memoryManager.AllocateClean<byte>(TableLength);
return base.Quantize(image, this.colors); return base.QuantizeFrame(image);
} }
finally finally
{ {
@ -293,7 +290,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization
if (this.Dither) if (this.Dither)
{ {
// Apply the dithering matrix. We have to reapply the value now as the original has changed. // Apply the dithering matrix. We have to reapply the value now as the original has changed.
this.DitherType.Dither(source, sourcePixel, transformedPixel, x, y, 0, 0, width, height); this.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, 0, 0, width, height);
} }
output[(y * source.Width) + x] = pixelValue; output[(y * source.Width) + x] = pixelValue;
@ -873,5 +870,56 @@ namespace SixLabors.ImageSharp.Processing.Quantization
return tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)]; return tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)];
} }
/// <summary>
/// Represents a box color cube.
/// </summary>
private struct Box
{
/// <summary>
/// Gets or sets the min red value, exclusive.
/// </summary>
public int R0;
/// <summary>
/// Gets or sets the max red value, inclusive.
/// </summary>
public int R1;
/// <summary>
/// Gets or sets the min green value, exclusive.
/// </summary>
public int G0;
/// <summary>
/// Gets or sets the max green value, inclusive.
/// </summary>
public int G1;
/// <summary>
/// Gets or sets the min blue value, exclusive.
/// </summary>
public int B0;
/// <summary>
/// Gets or sets the max blue value, inclusive.
/// </summary>
public int B1;
/// <summary>
/// Gets or sets the min alpha value, exclusive.
/// </summary>
public int A0;
/// <summary>
/// Gets or sets the max alpha value, inclusive.
/// </summary>
public int A1;
/// <summary>
/// Gets or sets the volume.
/// </summary>
public int Volume;
}
} }
} }

28
src/ImageSharp/Processing/Quantization/IQuantizer.cs

@ -0,0 +1,28 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
using SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers;
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Provides methods for allowing quantization of images pixels with configurable dithering.
/// </summary>
public interface IQuantizer
{
/// <summary>
/// Gets the error diffusion algorithm to apply to the output image.
/// </summary>
IErrorDiffuser Diffuser { get; }
/// <summary>
/// Creates the generic frame quantizer
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/></returns>
IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>;
}
}

42
src/ImageSharp/Processing/Quantization/IQuantizer{TPixel}.cs

@ -1,42 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Provides methods for for allowing quantization of images pixels with configurable dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public interface IQuantizer<TPixel> : IQuantizer
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Quantize an image and return the resulting output pixels.
/// </summary>
/// <param name="image">The image to quantize.</param>
/// <param name="maxColors">The maximum number of colors to return.</param>
/// <returns>
/// A <see cref="T:QuantizedImage"/> representing a quantized version of the image pixels.
/// </returns>
QuantizedFrame<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors);
}
/// <summary>
/// Provides methods for allowing quantization of images pixels with configurable dithering.
/// </summary>
public interface IQuantizer
{
/// <summary>
/// Gets or sets a value indicating whether to apply dithering to the output image.
/// </summary>
bool Dither { get; set; }
/// <summary>
/// Gets or sets the dithering algorithm to apply to the output image.
/// </summary>
IErrorDiffuser DitherType { get; set; }
}
}

29
src/ImageSharp/Processing/Quantization/KnownQuantizers.cs

@ -0,0 +1,29 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Contains reusable static instances of known quantizing algorithms
/// </summary>
public static class KnownQuantizers
{
/// <summary>
/// Gets the adaptive Octree quantizer. Fast with good quality.
/// The quantizer only supports a single alpha value.
/// </summary>
public static IQuantizer Octree { get; } = new OctreeQuantizer();
/// <summary>
/// Gets the Xiaolin Wu's Color Quantizer which generates high quality output.
/// The quantizer supports multiple alpha values.
/// </summary>
public static IQuantizer Wu { get; } = new WuQuantizer();
/// <summary>
/// Gets the palette based, Using the collection of web-safe colors.
/// The quantizer supports multiple alpha values.
/// </summary>
public static IQuantizer Palette { get; } = new PaletteQuantizer();
}
}

83
src/ImageSharp/Processing/Quantization/OctreeQuantizer.cs

@ -0,0 +1,83 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
using SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers;
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Allows the quantization of images pixels using Octrees.
/// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/>
/// <para>
/// By default the quantizer uses <see cref="KnownDiffusers.FloydSteinberg"/> dithering and a color palette of a maximum length of <value>255</value>
/// </para>
/// </summary>
public class OctreeQuantizer : IQuantizer
{
/// <summary>
/// Initializes a new instance of the <see cref="OctreeQuantizer"/> class.
/// </summary>
public OctreeQuantizer()
: this(true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OctreeQuantizer"/> class.
/// </summary>
/// <param name="maxColors">The maximum number of colors to hold in the color palette</param>
public OctreeQuantizer(int maxColors)
: this(GetDiffuser(true), maxColors)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OctreeQuantizer"/> class.
/// </summary>
/// <param name="dither">Whether to apply dithering to the output image</param>
public OctreeQuantizer(bool dither)
: this(GetDiffuser(dither), 255)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OctreeQuantizer"/> class.
/// </summary>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
public OctreeQuantizer(IErrorDiffuser diffuser)
: this(diffuser, 255)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OctreeQuantizer"/> class.
/// </summary>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette</param>
public OctreeQuantizer(IErrorDiffuser diffuser, int maxColors)
{
Guard.MustBeBetweenOrEqualTo(maxColors, 1, 255, nameof(maxColors));
this.Diffuser = diffuser;
this.MaxColors = maxColors;
}
/// <inheritdoc />
public IErrorDiffuser Diffuser { get; }
/// <summary>
/// Gets the maximum number of colors to hold in the color palette.
/// </summary>
public int MaxColors { get; }
/// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
=> new OctreeFrameQuantizer<TPixel>(this);
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
}
}

65
src/ImageSharp/Processing/Quantization/PaletteQuantizer.cs

@ -0,0 +1,65 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
using SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers;
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Allows the quantization of images pixels using web safe colors defined in the CSS Color Module Level 4.
/// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/> Override this class to provide your own palette.
/// <para>
/// By default the quantizer uses <see cref="KnownDiffusers.FloydSteinberg"/> dithering and the <see cref="NamedColors{TPixel}.WebSafePalette"/>
/// </para>
/// </summary>
public class PaletteQuantizer : IQuantizer
{
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
public PaletteQuantizer()
: this(true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
/// <param name="dither">Whether to apply dithering to the output image</param>
public PaletteQuantizer(bool dither)
: this(GetDiffuser(dither))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
public PaletteQuantizer(IErrorDiffuser diffuser)
{
this.Diffuser = diffuser;
}
/// <inheritdoc />
public IErrorDiffuser Diffuser { get; }
/// <summary>
/// Gets the palette to use to quantize the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>The <see cref="T:TPixel[]"/></returns>
public virtual TPixel[] GetPalette<TPixel>()
where TPixel : struct, IPixel<TPixel>
=> NamedColors<TPixel>.WebSafePalette;
/// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
=> new PaletteFrameQuantizer<TPixel>(this);
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
}
}

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

@ -2,16 +2,16 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Quantization.Processors namespace SixLabors.ImageSharp.Processing.Quantization.Processors
{ {
/// <summary> /// <summary>
/// Enables the quantization of images to remove the number of colors used in the image palette. /// Enables the quantization of images to reduce the number of colors used in the image palette.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal class QuantizeProcessor<TPixel> : ImageProcessor<TPixel> internal class QuantizeProcessor<TPixel> : ImageProcessor<TPixel>
@ -21,51 +21,38 @@ namespace SixLabors.ImageSharp.Processing.Quantization.Processors
/// Initializes a new instance of the <see cref="QuantizeProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="QuantizeProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="quantizer">The quantizer used to reduce the color palette</param> /// <param name="quantizer">The quantizer used to reduce the color palette</param>
/// <param name="maxColors">The maximum number of colors to reduce the palette to</param> public QuantizeProcessor(IQuantizer quantizer)
public QuantizeProcessor(IQuantizer<TPixel> quantizer, int maxColors)
{ {
Guard.NotNull(quantizer, nameof(quantizer)); Guard.NotNull(quantizer, nameof(quantizer));
Guard.MustBeGreaterThan(maxColors, 0, nameof(maxColors));
this.Quantizer = quantizer; this.Quantizer = quantizer;
this.MaxColors = maxColors;
} }
/// <summary> /// <summary>
/// Gets the quantizer /// Gets the quantizer
/// </summary> /// </summary>
public IQuantizer<TPixel> Quantizer { get; } public IQuantizer Quantizer { get; }
/// <summary>
/// Gets the maximum number of palette colors
/// </summary>
public int MaxColors { get; }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
QuantizedFrame<TPixel> quantized = this.Quantizer.Quantize(source, this.MaxColors); IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>();
QuantizedFrame<TPixel> quantized = executor.QuantizeFrame(source);
int paletteCount = quantized.Palette.Length - 1; int paletteCount = quantized.Palette.Length - 1;
using (Buffer2D<TPixel> pixels = source.MemoryManager.Allocate2D<TPixel>(quantized.Width, quantized.Height)) // Not parallel to remove "quantized" closure allocation.
// We can operate directly on the source here as we've already read it to get the
// quantized result
for (int y = 0; y < source.Height; y++)
{ {
Parallel.For( Span<TPixel> row = source.GetPixelRowSpan(y);
0, int yy = y * source.Width;
pixels.Height,
configuration.ParallelOptions, for (int x = 0; x < source.Width; x++)
y => {
{ int i = x + yy;
Span<TPixel> row = pixels.GetRowSpan(y); TPixel color = quantized.Palette[Math.Min(paletteCount, quantized.Pixels[i])];
int yy = y * pixels.Width; row[x] = color;
for (int x = 0; x < pixels.Width; x++) }
{
int i = x + yy;
TPixel color = quantized.Palette[Math.Min(paletteCount, quantized.Pixels[i])];
row[x] = color;
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, pixels);
} }
} }
} }

29
src/ImageSharp/Processing/Quantization/QuantizationMode.cs

@ -1,29 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Provides enumeration over how an image should be quantized.
/// </summary>
public enum QuantizationMode
{
/// <summary>
/// An adaptive Octree quantizer. Fast with good quality.
/// The quantizer only supports a single alpha value.
/// </summary>
Octree,
/// <summary>
/// Xiaolin Wu's Color Quantizer which generates high quality output.
/// The quantizer supports multiple alpha values.
/// </summary>
Wu,
/// <summary>
/// Palette based, Uses the collection of web-safe colors by default.
/// The quantizer supports multiple alpha values.
/// </summary>
Palette
}
}

31
src/ImageSharp/Processing/Quantization/QuantizeExtensions.cs

@ -12,34 +12,14 @@ namespace SixLabors.ImageSharp.Processing.Quantization
public static class QuantizeExtensions public static class QuantizeExtensions
{ {
/// <summary> /// <summary>
/// Applies quantization to the image. /// Applies quantization to the image using the <see cref="OctreeQuantizer"/>.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="mode">The quantization mode to apply to perform the operation.</param>
/// <param name="maxColors">The maximum number of colors to return. Defaults to 256.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, QuantizationMode mode = QuantizationMode.Octree, int maxColors = 256) public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ => Quantize(source, KnownQuantizers.Octree);
IQuantizer<TPixel> quantizer;
switch (mode)
{
case QuantizationMode.Wu:
quantizer = new WuQuantizer<TPixel>();
break;
case QuantizationMode.Palette:
quantizer = new PaletteQuantizer<TPixel>();
break;
default:
quantizer = new OctreeQuantizer<TPixel>();
break;
}
return Quantize(source, quantizer, maxColors);
}
/// <summary> /// <summary>
/// Applies quantization to the image. /// Applies quantization to the image.
@ -47,10 +27,9 @@ namespace SixLabors.ImageSharp.Processing.Quantization
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="quantizer">The quantizer to apply to perform the operation.</param> /// <param name="quantizer">The quantizer to apply to perform the operation.</param>
/// <param name="maxColors">The maximum number of colors to return.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, IQuantizer<TPixel> quantizer, int maxColors) public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, IQuantizer quantizer)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new QuantizeProcessor<TPixel>(quantizer, maxColors)); => source.ApplyProcessor(new QuantizeProcessor<TPixel>(quantizer));
} }
} }

82
src/ImageSharp/Processing/Quantization/WuQuantizer.cs

@ -0,0 +1,82 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Dithering;
using SixLabors.ImageSharp.Processing.Dithering.ErrorDiffusion;
using SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers;
namespace SixLabors.ImageSharp.Processing.Quantization
{
/// <summary>
/// Allows the quantization of images pixels using Xiaolin Wu's Color Quantizer <see href="http://www.ece.mcmaster.ca/~xwu/cq.c"/>
/// <para>
/// By default the quantizer uses <see cref="KnownDiffusers.FloydSteinberg"/> dithering and a color palette of a maximum length of <value>255</value>
/// </para>
/// </summary>
public class WuQuantizer : IQuantizer
{
/// <summary>
/// Initializes a new instance of the <see cref="WuQuantizer"/> class.
/// </summary>
public WuQuantizer()
: this(true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WuQuantizer"/> class.
/// </summary>
/// <param name="maxColors">The maximum number of colors to hold in the color palette</param>
public WuQuantizer(int maxColors)
: this(GetDiffuser(true), maxColors)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WuQuantizer"/> class.
/// </summary>
/// <param name="dither">Whether to apply dithering to the output image</param>
public WuQuantizer(bool dither)
: this(GetDiffuser(dither), 255)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WuQuantizer"/> class.
/// </summary>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
public WuQuantizer(IErrorDiffuser diffuser)
: this(diffuser, 255)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WuQuantizer"/> class.
/// </summary>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette</param>
public WuQuantizer(IErrorDiffuser diffuser, int maxColors)
{
Guard.MustBeBetweenOrEqualTo(maxColors, 1, 255, nameof(maxColors));
this.Diffuser = diffuser;
this.MaxColors = maxColors;
}
/// <inheritdoc />
public IErrorDiffuser Diffuser { get; }
/// <summary>
/// Gets the maximum number of colors to hold in the color palette.
/// </summary>
public int MaxColors { get; }
/// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
=> new WuFrameQuantizer<TPixel>(this);
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
}
}

2
src/ImageSharp/Processing/Transforms/AnchorPosition.cs → src/ImageSharp/Processing/Transforms/AnchorPositionMode.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Enumerated anchor positions to apply to resized images. /// Enumerated anchor positions to apply to resized images.
/// </summary> /// </summary>
public enum AnchorPosition public enum AnchorPositionMode
{ {
/// <summary> /// <summary>
/// Anchors the position of the image to the center of it's bounding container. /// Anchors the position of the image to the center of it's bounding container.

6
src/ImageSharp/Processing/Transforms/FlipExtensions.cs

@ -16,10 +16,10 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param> /// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param> /// <param name="flipMode">The <see cref="FlipMode"/> to perform the flip.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Flip<TPixel>(this IImageProcessingContext<TPixel> source, FlipType flipType) public static IImageProcessingContext<TPixel> Flip<TPixel>(this IImageProcessingContext<TPixel> source, FlipMode flipMode)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new FlipProcessor<TPixel>(flipType)); => source.ApplyProcessor(new FlipProcessor<TPixel>(flipMode));
} }
} }

2
src/ImageSharp/Processing/Transforms/FlipType.cs → src/ImageSharp/Processing/Transforms/FlipMode.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Provides enumeration over how a image should be flipped. /// Provides enumeration over how a image should be flipped.
/// </summary> /// </summary>
public enum FlipType public enum FlipMode
{ {
/// <summary> /// <summary>
/// Don't flip the image. /// Don't flip the image.

2
src/ImageSharp/Processing/Transforms/ResampleMode.cs → src/ImageSharp/Processing/Transforms/KnownResamplers.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Contains reusable static instances of known resampling algorithms /// Contains reusable static instances of known resampling algorithms
/// </summary> /// </summary>
public static class ResampleMode public static class KnownResamplers
{ {
/// <summary> /// <summary>
/// Gets the Bicubic sampler that implements the bicubic kernel algorithm W(x) /// Gets the Bicubic sampler that implements the bicubic kernel algorithm W(x)

2
src/ImageSharp/Processing/Transforms/OrientationType.cs → src/ImageSharp/Processing/Transforms/OrientationMode.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Enumerates the available orientation values supplied by EXIF metadata. /// Enumerates the available orientation values supplied by EXIF metadata.
/// </summary> /// </summary>
internal enum OrientationType : ushort internal enum OrientationMode : ushort
{ {
/// <summary> /// <summary>
/// Unknown rotation. /// Unknown rotation.

2
src/ImageSharp/Processing/Transforms/PadExtensions.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
{ {
Size = new Size(width, height), Size = new Size(width, height),
Mode = ResizeMode.BoxPad, Mode = ResizeMode.BoxPad,
Sampler = ResampleMode.NearestNeighbor Sampler = KnownResamplers.NearestNeighbor
}; };
return source.Resize(options); return source.Resize(options);

54
src/ImageSharp/Processing/Transforms/Processors/AutoOrientProcessor.cs

@ -19,42 +19,42 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle) protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{ {
OrientationType orientation = GetExifOrientation(source); OrientationMode orientation = GetExifOrientation(source);
Size size = sourceRectangle.Size; Size size = sourceRectangle.Size;
switch (orientation) switch (orientation)
{ {
case OrientationType.TopRight: case OrientationMode.TopRight:
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle); new FlipProcessor<TPixel>(FlipMode.Horizontal).Apply(source, sourceRectangle);
break; break;
case OrientationType.BottomRight: case OrientationMode.BottomRight:
new RotateProcessor<TPixel>((int)RotateType.Rotate180, size).Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateMode.Rotate180, size).Apply(source, sourceRectangle);
break; break;
case OrientationType.BottomLeft: case OrientationMode.BottomLeft:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle); new FlipProcessor<TPixel>(FlipMode.Vertical).Apply(source, sourceRectangle);
break; break;
case OrientationType.LeftTop: case OrientationMode.LeftTop:
new RotateProcessor<TPixel>((int)RotateType.Rotate90, size).Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle); new FlipProcessor<TPixel>(FlipMode.Horizontal).Apply(source, sourceRectangle);
break; break;
case OrientationType.RightTop: case OrientationMode.RightTop:
new RotateProcessor<TPixel>((int)RotateType.Rotate90, size).Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle);
break; break;
case OrientationType.RightBottom: case OrientationMode.RightBottom:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle); new FlipProcessor<TPixel>(FlipMode.Vertical).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateType.Rotate270, size).Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle);
break; break;
case OrientationType.LeftBottom: case OrientationMode.LeftBottom:
new RotateProcessor<TPixel>((int)RotateType.Rotate270, size).Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle);
break; break;
case OrientationType.Unknown: case OrientationMode.Unknown:
case OrientationType.TopLeft: case OrientationMode.TopLeft:
default: default:
break; break;
} }
@ -70,32 +70,32 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// Returns the current EXIF orientation /// Returns the current EXIF orientation
/// </summary> /// </summary>
/// <param name="source">The image to auto rotate.</param> /// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="OrientationType"/></returns> /// <returns>The <see cref="OrientationMode"/></returns>
private static OrientationType GetExifOrientation(Image<TPixel> source) private static OrientationMode GetExifOrientation(Image<TPixel> source)
{ {
if (source.MetaData.ExifProfile == null) if (source.MetaData.ExifProfile == null)
{ {
return OrientationType.Unknown; return OrientationMode.Unknown;
} }
ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation); ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null) if (value == null)
{ {
return OrientationType.Unknown; return OrientationMode.Unknown;
} }
OrientationType orientation; OrientationMode orientation;
if (value.DataType == ExifDataType.Short) if (value.DataType == ExifDataType.Short)
{ {
orientation = (OrientationType)value.Value; orientation = (OrientationMode)value.Value;
} }
else else
{ {
orientation = (OrientationType)Convert.ToUInt16(value.Value); orientation = (OrientationMode)Convert.ToUInt16(value.Value);
source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation); source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation);
} }
source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)OrientationType.TopLeft); source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)OrientationMode.TopLeft);
return orientation; return orientation;
} }

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

@ -21,27 +21,27 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FlipProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="FlipProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="flipType">The <see cref="FlipType"/> used to perform flipping.</param> /// <param name="flipMode">The <see cref="Transforms.FlipMode"/> used to perform flipping.</param>
public FlipProcessor(FlipType flipType) public FlipProcessor(FlipMode flipMode)
{ {
this.FlipType = flipType; this.FlipMode = flipMode;
} }
/// <summary> /// <summary>
/// Gets the <see cref="FlipType"/> used to perform flipping. /// Gets the <see cref="Transforms.FlipMode"/> used to perform flipping.
/// </summary> /// </summary>
public FlipType FlipType { get; } public FlipMode FlipMode { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
switch (this.FlipType) switch (this.FlipMode)
{ {
// No default needed as we have already set the pixels. // No default needed as we have already set the pixels.
case FlipType.Vertical: case FlipMode.Vertical:
this.FlipX(source, configuration); this.FlipX(source, configuration);
break; break;
case FlipType.Horizontal: case FlipMode.Horizontal:
this.FlipY(source, configuration); this.FlipY(source, configuration);
break; break;
} }

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

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <param name="degrees">The angle of rotation in degrees.</param> /// <param name="degrees">The angle of rotation in degrees.</param>
/// <param name="sourceSize">The source image size</param> /// <param name="sourceSize">The source image size</param>
public RotateProcessor(float degrees, Size sourceSize) public RotateProcessor(float degrees, Size sourceSize)
: this(degrees, ResampleMode.Bicubic, sourceSize) : this(degrees, KnownResamplers.Bicubic, sourceSize)
{ {
} }

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

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <param name="degreesY">The angle in degrees to perform the skew along the y-axis.</param> /// <param name="degreesY">The angle in degrees to perform the skew along the y-axis.</param>
/// <param name="sourceSize">The source image size</param> /// <param name="sourceSize">The source image size</param>
public SkewProcessor(float degreesX, float degreesY, Size sourceSize) public SkewProcessor(float degreesX, float degreesY, Size sourceSize)
: this(degreesX, degreesY, ResampleMode.Bicubic, sourceSize) : this(degreesX, degreesY, KnownResamplers.Bicubic, sourceSize)
{ {
} }

8
src/ImageSharp/Processing/Transforms/ResizeExtensions.cs

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks> /// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, Size size) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, Size size)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Resize(source, size.Width, size.Height, ResampleMode.Bicubic, false); => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, false);
/// <summary> /// <summary>
/// Resizes an image to the given <see cref="Size"/>. /// Resizes an image to the given <see cref="Size"/>.
@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks> /// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, Size size, bool compand) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, Size size, bool compand)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Resize(source, size.Width, size.Height, ResampleMode.Bicubic, compand); => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, compand);
/// <summary> /// <summary>
/// Resizes an image to the given width and height. /// Resizes an image to the given width and height.
@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks> /// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Resize(source, width, height, ResampleMode.Bicubic, false); => Resize(source, width, height, KnownResamplers.Bicubic, false);
/// <summary> /// <summary>
/// Resizes an image to the given width and height. /// Resizes an image to the given width and height.
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks> /// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, bool compand) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, bool compand)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Resize(source, width, height, ResampleMode.Bicubic, compand); => Resize(source, width, height, KnownResamplers.Bicubic, compand);
/// <summary> /// <summary>
/// Resizes an image to the given width and height with the given sampler. /// Resizes an image to the given width and height with the given sampler.

64
src/ImageSharp/Processing/Transforms/ResizeHelper.cs

@ -87,14 +87,14 @@ namespace SixLabors.ImageSharp.Processing.Transforms
{ {
switch (options.Position) switch (options.Position)
{ {
case AnchorPosition.Top: case AnchorPositionMode.Top:
case AnchorPosition.TopLeft: case AnchorPositionMode.TopLeft:
case AnchorPosition.TopRight: case AnchorPositionMode.TopRight:
destinationY = 0; destinationY = 0;
break; break;
case AnchorPosition.Bottom: case AnchorPositionMode.Bottom:
case AnchorPosition.BottomLeft: case AnchorPositionMode.BottomLeft:
case AnchorPosition.BottomRight: case AnchorPositionMode.BottomRight:
destinationY = (int)MathF.Round(height - (sourceHeight * ratio)); destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
break; break;
default: default:
@ -128,14 +128,14 @@ namespace SixLabors.ImageSharp.Processing.Transforms
{ {
switch (options.Position) switch (options.Position)
{ {
case AnchorPosition.Left: case AnchorPositionMode.Left:
case AnchorPosition.TopLeft: case AnchorPositionMode.TopLeft:
case AnchorPosition.BottomLeft: case AnchorPositionMode.BottomLeft:
destinationX = 0; destinationX = 0;
break; break;
case AnchorPosition.Right: case AnchorPositionMode.Right:
case AnchorPosition.TopRight: case AnchorPositionMode.TopRight:
case AnchorPosition.BottomRight: case AnchorPositionMode.BottomRight:
destinationX = (int)MathF.Round(width - (sourceWidth * ratio)); destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
break; break;
default: default:
@ -177,14 +177,14 @@ namespace SixLabors.ImageSharp.Processing.Transforms
switch (options.Position) switch (options.Position)
{ {
case AnchorPosition.Left: case AnchorPositionMode.Left:
case AnchorPosition.TopLeft: case AnchorPositionMode.TopLeft:
case AnchorPosition.BottomLeft: case AnchorPositionMode.BottomLeft:
destinationX = 0; destinationX = 0;
break; break;
case AnchorPosition.Right: case AnchorPositionMode.Right:
case AnchorPosition.TopRight: case AnchorPositionMode.TopRight:
case AnchorPosition.BottomRight: case AnchorPositionMode.BottomRight:
destinationX = (int)MathF.Round(width - (sourceWidth * ratio)); destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
break; break;
default: default:
@ -199,14 +199,14 @@ namespace SixLabors.ImageSharp.Processing.Transforms
switch (options.Position) switch (options.Position)
{ {
case AnchorPosition.Top: case AnchorPositionMode.Top:
case AnchorPosition.TopLeft: case AnchorPositionMode.TopLeft:
case AnchorPosition.TopRight: case AnchorPositionMode.TopRight:
destinationY = 0; destinationY = 0;
break; break;
case AnchorPosition.Bottom: case AnchorPositionMode.Bottom:
case AnchorPosition.BottomLeft: case AnchorPositionMode.BottomLeft:
case AnchorPosition.BottomRight: case AnchorPositionMode.BottomRight:
destinationY = (int)MathF.Round(height - (sourceHeight * ratio)); destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
break; break;
default: default:
@ -247,35 +247,35 @@ namespace SixLabors.ImageSharp.Processing.Transforms
switch (options.Position) switch (options.Position)
{ {
case AnchorPosition.Left: case AnchorPositionMode.Left:
destinationY = (height - sourceHeight) / 2; destinationY = (height - sourceHeight) / 2;
destinationX = 0; destinationX = 0;
break; break;
case AnchorPosition.Right: case AnchorPositionMode.Right:
destinationY = (height - sourceHeight) / 2; destinationY = (height - sourceHeight) / 2;
destinationX = width - sourceWidth; destinationX = width - sourceWidth;
break; break;
case AnchorPosition.TopRight: case AnchorPositionMode.TopRight:
destinationY = 0; destinationY = 0;
destinationX = width - sourceWidth; destinationX = width - sourceWidth;
break; break;
case AnchorPosition.Top: case AnchorPositionMode.Top:
destinationY = 0; destinationY = 0;
destinationX = (width - sourceWidth) / 2; destinationX = (width - sourceWidth) / 2;
break; break;
case AnchorPosition.TopLeft: case AnchorPositionMode.TopLeft:
destinationY = 0; destinationY = 0;
destinationX = 0; destinationX = 0;
break; break;
case AnchorPosition.BottomRight: case AnchorPositionMode.BottomRight:
destinationY = height - sourceHeight; destinationY = height - sourceHeight;
destinationX = width - sourceWidth; destinationX = width - sourceWidth;
break; break;
case AnchorPosition.Bottom: case AnchorPositionMode.Bottom:
destinationY = height - sourceHeight; destinationY = height - sourceHeight;
destinationX = (width - sourceWidth) / 2; destinationX = (width - sourceWidth) / 2;
break; break;
case AnchorPosition.BottomLeft: case AnchorPositionMode.BottomLeft:
destinationY = height - sourceHeight; destinationY = height - sourceHeight;
destinationX = 0; destinationX = 0;
break; break;

2
src/ImageSharp/Processing/Transforms/ResizeMode.cs

@ -4,7 +4,7 @@
namespace SixLabors.ImageSharp.Processing.Transforms namespace SixLabors.ImageSharp.Processing.Transforms
{ {
/// <summary> /// <summary>
/// Enumerated resize modes to apply to images. /// Provides enumeration over how the image should be resized.
/// </summary> /// </summary>
public enum ResizeMode public enum ResizeMode
{ {

4
src/ImageSharp/Processing/Transforms/ResizeOptions.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Gets or sets the anchor position. /// Gets or sets the anchor position.
/// </summary> /// </summary>
public AnchorPosition Position { get; set; } = AnchorPosition.Center; public AnchorPositionMode Position { get; set; } = AnchorPositionMode.Center;
/// <summary> /// <summary>
/// Gets or sets the center coordinates. /// Gets or sets the center coordinates.
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Gets or sets the sampler to perform the resize operation. /// Gets or sets the sampler to perform the resize operation.
/// </summary> /// </summary>
public IResampler Sampler { get; set; } = ResampleMode.Bicubic; public IResampler Sampler { get; set; } = KnownResamplers.Bicubic;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to compress /// Gets or sets a value indicating whether to compress

8
src/ImageSharp/Processing/Transforms/RotateExtensions.cs

@ -17,11 +17,11 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate.</param> /// <param name="source">The image to rotate.</param>
/// <param name="rotateType">The <see cref="RotateType"/> to perform the rotation.</param> /// <param name="rotateMode">The <see cref="RotateMode"/> to perform the rotation.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, RotateType rotateType) public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, RotateMode rotateMode)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Rotate(source, (float)rotateType); => Rotate(source, (float)rotateMode);
/// <summary> /// <summary>
/// Rotates an image by the given angle in degrees. /// Rotates an image by the given angle in degrees.
@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees) public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Rotate(source, degrees, ResampleMode.Bicubic); => Rotate(source, degrees, KnownResamplers.Bicubic);
/// <summary> /// <summary>
/// Rotates an image by the given angle in degrees using the specified sampling algorithm. /// Rotates an image by the given angle in degrees using the specified sampling algorithm.

8
src/ImageSharp/Processing/Transforms/RotateFlipExtensions.cs

@ -15,11 +15,11 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param> /// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="rotateType">The <see cref="RotateType"/> to perform the rotation.</param> /// <param name="rotateMode">The <see cref="RotateMode"/> to perform the rotation.</param>
/// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param> /// <param name="flipMode">The <see cref="FlipMode"/> to perform the flip.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> RotateFlip<TPixel>(this IImageProcessingContext<TPixel> source, RotateType rotateType, FlipType flipType) public static IImageProcessingContext<TPixel> RotateFlip<TPixel>(this IImageProcessingContext<TPixel> source, RotateMode rotateMode, FlipMode flipMode)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Rotate(rotateType).Flip(flipType); => source.Rotate(rotateMode).Flip(flipMode);
} }
} }

2
src/ImageSharp/Processing/Transforms/RotateType.cs → src/ImageSharp/Processing/Transforms/RotateMode.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <summary> /// <summary>
/// Provides enumeration over how the image should be rotated. /// Provides enumeration over how the image should be rotated.
/// </summary> /// </summary>
public enum RotateType public enum RotateMode
{ {
/// <summary> /// <summary>
/// Do not rotate the image. /// Do not rotate the image.

2
src/ImageSharp/Processing/Transforms/SkewExtensions.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY) public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Skew(source, degreesX, degreesY, ResampleMode.Bicubic); => Skew(source, degreesX, degreesY, KnownResamplers.Bicubic);
/// <summary> /// <summary>
/// Skews an image by the given angles in degrees using the specified sampling algorithm. /// Skews an image by the given angles in degrees using the specified sampling algorithm.

4
src/ImageSharp/Processing/Transforms/TransformExtensions.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix3x2 matrix) public static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix3x2 matrix)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Transform(source, matrix, ResampleMode.Bicubic); => Transform(source, matrix, KnownResamplers.Bicubic);
/// <summary> /// <summary>
/// Transforms an image by the given matrix using the specified sampling algorithm. /// Transforms an image by the given matrix using the specified sampling algorithm.
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
internal static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix4x4 matrix) internal static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix4x4 matrix)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Transform(source, matrix, ResampleMode.Bicubic); => Transform(source, matrix, KnownResamplers.Bicubic);
/// <summary> /// <summary>
/// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm.

53
tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs

@ -3,20 +3,15 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization;
using CoreImage = SixLabors.ImageSharp.Image;
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Processing.Quantization;
using CoreImage = ImageSharp.Image;
/// <summary> /// <summary>
/// Benchmarks saving png files using different quantizers. System.Drawing cannot save indexed png files so we cannot compare. /// Benchmarks saving png files using different quantizers. System.Drawing cannot save indexed png files so we cannot compare.
/// </summary> /// </summary>
@ -35,8 +30,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
if (this.bmpStream == null) if (this.bmpStream == null)
{ {
string path = this.LargeImage string path = this.LargeImage
? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg" ? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg"
: "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp"; : "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp";
this.bmpStream = File.OpenRead(path); this.bmpStream = File.OpenRead(path);
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream); this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0; this.bmpStream.Position = 0;
@ -53,20 +49,20 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Baseline = true, Description = "ImageSharp Octree Png")] [Benchmark(Baseline = true, Description = "ImageSharp Octree Png")]
public void PngCoreOctree() public void PngCoreOctree()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
PngEncoder encoder = new PngEncoder() { Quantizer = new OctreeQuantizer<Rgba32>(), PaletteSize = 256 }; var encoder = new PngEncoder { Quantizer = new OctreeQuantizer() };
this.bmpCore.SaveAsPng(memoryStream, encoder); this.bmpCore.SaveAsPng(memoryStream, encoder);
} }
} }
[Benchmark(Description = "ImageSharp Octree NoDither Png")] [Benchmark(Description = "ImageSharp Octree NoDither Png")]
public void PngCoreOctreeNoDIther() public void PngCoreOctreeNoDither()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
PngEncoder options = new PngEncoder() { Quantizer = new OctreeQuantizer<Rgba32> { Dither = false }, PaletteSize = 256 }; var options = new PngEncoder { Quantizer = new OctreeQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
@ -75,9 +71,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp Palette Png")] [Benchmark(Description = "ImageSharp Palette Png")]
public void PngCorePalette() public void PngCorePalette()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
PngEncoder options = new PngEncoder() { Quantizer = new PaletteQuantizer<Rgba32>(), PaletteSize = 256 }; var options = new PngEncoder { Quantizer = new PaletteQuantizer() };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
@ -86,9 +82,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp Palette NoDither Png")] [Benchmark(Description = "ImageSharp Palette NoDither Png")]
public void PngCorePaletteNoDither() public void PngCorePaletteNoDither()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
PngEncoder options = new PngEncoder() { Quantizer = new PaletteQuantizer<Rgba32> { Dither = false }, PaletteSize = 256 }; var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
@ -97,9 +93,20 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp Wu Png")] [Benchmark(Description = "ImageSharp Wu Png")]
public void PngCoreWu() public void PngCoreWu()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{
var options = new PngEncoder { Quantizer = new WuQuantizer() };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}
[Benchmark(Description = "ImageSharp Wu NoDither Png")]
public void PngCoreWuNoDither()
{
using (var memoryStream = new MemoryStream())
{ {
PngEncoder options = new PngEncoder() { Quantizer = new WuQuantizer<Rgba32>(), PaletteSize = 256 }; var options = new PngEncoder { Quantizer = new WuQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }

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

@ -70,12 +70,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
QuantizerBase<Rgba32> quantizer = this.UseOctreeQuantizer IQuantizer quantizer = this.UseOctreeQuantizer
? (QuantizerBase<Rgba32>) ?
new OctreeQuantizer<Rgba32>() (IQuantizer)new OctreeQuantizer()
: new PaletteQuantizer<Rgba32>(); : new PaletteQuantizer();
var options = new PngEncoder() { Quantizer = quantizer }; var options = new PngEncoder { Quantizer = quantizer };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
} }

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

@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests
// We pass a new rectangle here based on the dest bounds since we've offset the matrix // We pass a new rectangle here based on the dest bounds since we've offset the matrix
blend.Mutate(x => x.Transform( blend.Mutate(x => x.Transform(
centeredMatrix, centeredMatrix,
ResampleMode.Bicubic, KnownResamplers.Bicubic,
new Rectangle(0, 0, destBounds.Width, destBounds.Height))); new Rectangle(0, 0, destBounds.Width, destBounds.Height)));
var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2);

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

@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests
{ {
using (FileStream output = File.OpenWrite($"{path}/Octree-{file.FileName}")) using (FileStream output = File.OpenWrite($"{path}/Octree-{file.FileName}"))
{ {
image.Mutate(x => x.Quantize(QuantizationMode.Octree)); image.Mutate(x => x.Quantize(KnownQuantizers.Octree));
image.Save(output, mimeType); image.Save(output, mimeType);
} }
@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests
{ {
using (FileStream output = File.OpenWrite($"{path}/Wu-{file.FileName}")) using (FileStream output = File.OpenWrite($"{path}/Wu-{file.FileName}"))
{ {
image.Mutate(x => x.Quantize(QuantizationMode.Wu)); image.Mutate(x => x.Quantize(KnownQuantizers.Wu));
image.Save(output, mimeType); image.Save(output, mimeType);
} }
} }
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests
{ {
using (FileStream output = File.OpenWrite($"{path}/Palette-{file.FileName}")) using (FileStream output = File.OpenWrite($"{path}/Palette-{file.FileName}"))
{ {
image.Mutate(x => x.Quantize(QuantizationMode.Palette)); image.Mutate(x => x.Quantize(KnownQuantizers.Palette));
image.Save(output, mimeType); image.Save(output, mimeType);
} }
} }

64
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -7,6 +7,8 @@ using System.Linq;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization;
using Xunit; using Xunit;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
@ -22,31 +24,31 @@ namespace SixLabors.ImageSharp.Tests
/// <summary> /// <summary>
/// All types except Palette /// All types except Palette
/// </summary> /// </summary>
public static readonly TheoryData<PngColorType> PngColorTypes = new TheoryData<PngColorType>() public static readonly TheoryData<PngColorType> PngColorTypes = new TheoryData<PngColorType>
{ {
PngColorType.RgbWithAlpha, PngColorType.RgbWithAlpha,
PngColorType.Rgb, PngColorType.Rgb,
PngColorType.Grayscale, PngColorType.Grayscale,
PngColorType.GrayscaleWithAlpha, PngColorType.GrayscaleWithAlpha,
}; };
/// <summary> /// <summary>
/// All types except Palette /// All types except Palette
/// </summary> /// </summary>
public static readonly TheoryData<int> CompressionLevels = new TheoryData<int>() public static readonly TheoryData<int> CompressionLevels = new TheoryData<int>
{ {
1, 2, 3, 4, 5, 6, 7, 8, 9 1, 2, 3, 4, 5, 6, 7, 8, 9
}; };
public static readonly TheoryData<int> PaletteSizes = new TheoryData<int>() public static readonly TheoryData<int> PaletteSizes = new TheoryData<int>
{ {
30, 55, 100, 201, 255 30, 55, 100, 201, 255
}; };
public static readonly TheoryData<int> PaletteLargeOnly = new TheoryData<int>() public static readonly TheoryData<int> PaletteLargeOnly = new TheoryData<int>
{ {
80, 100, 120, 230 80, 100, 120, 230
}; };
[Theory] [Theory]
[WithFile(TestImages.Png.Palette8Bpp, nameof(PngColorTypes), PixelTypes.Rgba32)] [WithFile(TestImages.Png.Palette8Bpp, nameof(PngColorTypes), PixelTypes.Rgba32)]
@ -60,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests
{ {
TestPngEncoderCore(provider, pngColorType, appendPngColorType: true); TestPngEncoderCore(provider, pngColorType, appendPngColorType: true);
} }
[Theory] [Theory]
[WithTestPatternImages(nameof(PngColorTypes), 24, 24, PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24)] [WithTestPatternImages(nameof(PngColorTypes), 24, 24, PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24)]
public void IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, PngColorType pngColorType) public void IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, PngColorType pngColorType)
@ -76,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests
{ {
TestPngEncoderCore(provider, PngColorType.RgbWithAlpha, compressionLevel, appendCompressionLevel: true); TestPngEncoderCore(provider, PngColorType.RgbWithAlpha, compressionLevel, appendCompressionLevel: true);
} }
[Theory] [Theory]
[WithFile(TestImages.Png.Palette8Bpp, nameof(PaletteLargeOnly), PixelTypes.Rgba32)] [WithFile(TestImages.Png.Palette8Bpp, nameof(PaletteLargeOnly), PixelTypes.Rgba32)]
public void PaletteColorType_WuQuantizer<TPixel>(TestImageProvider<TPixel> provider, int paletteSize) public void PaletteColorType_WuQuantizer<TPixel>(TestImageProvider<TPixel> provider, int paletteSize)
@ -92,7 +94,7 @@ namespace SixLabors.ImageSharp.Tests
TestImageProvider<TPixel> provider, TestImageProvider<TPixel> provider,
PngColorType pngColorType, PngColorType pngColorType,
int compressionLevel = 6, int compressionLevel = 6,
int paletteSize = 0, int paletteSize = 255,
bool appendPngColorType = false, bool appendPngColorType = false,
bool appendPixelType = false, bool appendPixelType = false,
bool appendCompressionLevel = false, bool appendCompressionLevel = false,
@ -107,11 +109,11 @@ namespace SixLabors.ImageSharp.Tests
} }
var encoder = new PngEncoder var encoder = new PngEncoder
{ {
PngColorType = pngColorType, PngColorType = pngColorType,
CompressionLevel = compressionLevel, CompressionLevel = compressionLevel,
PaletteSize = paletteSize Quantizer = new WuQuantizer(paletteSize)
}; };
string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : ""; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : "";
string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : ""; string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : "";
@ -121,10 +123,10 @@ namespace SixLabors.ImageSharp.Tests
// Does DebugSave & load reference CompareToReferenceInput(): // Does DebugSave & load reference CompareToReferenceInput():
string actualOutputFile = ((ITestImageProvider)provider).Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); string actualOutputFile = ((ITestImageProvider)provider).Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType);
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType); string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType);
using (var actualImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder)) using (var actualImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder))
using (var referenceImage = Image.Load<TPixel>(referenceOutputFile, referenceDecoder)) using (var referenceImage = Image.Load<TPixel>(referenceOutputFile, referenceDecoder))
{ {
@ -136,7 +138,7 @@ namespace SixLabors.ImageSharp.Tests
} }
} }
} }
[Theory] [Theory]
[WithBlankImages(1, 1, PixelTypes.Rgba32)] [WithBlankImages(1, 1, PixelTypes.Rgba32)]
public void WritesFileMarker<TPixel>(TestImageProvider<TPixel> provider) public void WritesFileMarker<TPixel>(TestImageProvider<TPixel> provider)
@ -146,8 +148,8 @@ namespace SixLabors.ImageSharp.Tests
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
image.Save(ms, new PngEncoder()); image.Save(ms, new PngEncoder());
byte[] data = ms.ToArray().Take(8).ToArray(); byte[] data = ms.ToArray().Take(8).ToArray();
byte[] expected = { byte[] expected = {
0x89, // Set the high bit. 0x89, // Set the high bit.
0x50, // P 0x50, // P

2
tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs

@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests
this.collection.AddFrame(new Rgba32[0]); this.collection.AddFrame(new Rgba32[0]);
}); });
Assert.StartsWith("Value must be greater than or equal to 100.", ex.Message); Assert.StartsWith("Value 0 must be greater than or equal to 100.", ex.Message);
} }
[Fact] [Fact]

2
tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs

@ -6,6 +6,8 @@ using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests namespace SixLabors.ImageSharp.Tests

2
tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs

@ -9,6 +9,8 @@ using System.Text;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests namespace SixLabors.ImageSharp.Tests

2
tests/ImageSharp.Tests/Numerics/RationalTests.cs

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.Primitives;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests namespace SixLabors.ImageSharp.Tests

2
tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.Primitives;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests namespace SixLabors.ImageSharp.Tests

4
tests/ImageSharp.Tests/Processing/Binarization/BinaryDitherTest.cs

@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
public BinaryDitherTest() public BinaryDitherTest()
{ {
this.orderedDither = DitherMode.BayerDither4x4; this.orderedDither = KnownDitherers.BayerDither4x4;
this.errorDiffuser = DiffuseMode.FloydSteinberg; this.errorDiffuser = KnownDiffusers.FloydSteinberg;
} }
[Fact] [Fact]

4
tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs

@ -25,8 +25,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
public DitherTest() public DitherTest()
{ {
this.orderedDither = DitherMode.BayerDither4x4; this.orderedDither = KnownDitherers.BayerDither4x4;
this.errorDiffuser = DiffuseMode.FloydSteinberg; this.errorDiffuser = KnownDiffusers.FloydSteinberg;
} }
[Fact] [Fact]

20
tests/ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs

@ -17,19 +17,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Filters
public class ColorBlindnessTest : BaseImageOperationsExtensionTest public class ColorBlindnessTest : BaseImageOperationsExtensionTest
{ {
public static IEnumerable<object[]> TheoryData = new[] { public static IEnumerable<object[]> TheoryData = new[] {
new object[]{ new TestType<AchromatomalyProcessor<Rgba32>>(), ColorBlindness.Achromatomaly }, new object[]{ new TestType<AchromatomalyProcessor<Rgba32>>(), ColorBlindnessMode.Achromatomaly },
new object[]{ new TestType<AchromatopsiaProcessor<Rgba32>>(), ColorBlindness.Achromatopsia }, new object[]{ new TestType<AchromatopsiaProcessor<Rgba32>>(), ColorBlindnessMode.Achromatopsia },
new object[]{ new TestType<DeuteranomalyProcessor<Rgba32>>(), ColorBlindness.Deuteranomaly }, new object[]{ new TestType<DeuteranomalyProcessor<Rgba32>>(), ColorBlindnessMode.Deuteranomaly },
new object[]{ new TestType<DeuteranopiaProcessor<Rgba32>>(), ColorBlindness.Deuteranopia }, new object[]{ new TestType<DeuteranopiaProcessor<Rgba32>>(), ColorBlindnessMode.Deuteranopia },
new object[]{ new TestType<ProtanomalyProcessor<Rgba32>>(), ColorBlindness.Protanomaly }, new object[]{ new TestType<ProtanomalyProcessor<Rgba32>>(), ColorBlindnessMode.Protanomaly },
new object[]{ new TestType<ProtanopiaProcessor<Rgba32>>(), ColorBlindness.Protanopia }, new object[]{ new TestType<ProtanopiaProcessor<Rgba32>>(), ColorBlindnessMode.Protanopia },
new object[]{ new TestType<TritanomalyProcessor<Rgba32>>(), ColorBlindness.Tritanomaly }, new object[]{ new TestType<TritanomalyProcessor<Rgba32>>(), ColorBlindnessMode.Tritanomaly },
new object[]{ new TestType<TritanopiaProcessor<Rgba32>>(), ColorBlindness.Tritanopia } new object[]{ new TestType<TritanopiaProcessor<Rgba32>>(), ColorBlindnessMode.Tritanopia }
}; };
[Theory] [Theory]
[MemberData(nameof(TheoryData))] [MemberData(nameof(TheoryData))]
public void ColorBlindness_CorrectProcessor<T>(TestType<T> testType, ColorBlindness colorBlindness) public void ColorBlindness_CorrectProcessor<T>(TestType<T> testType, ColorBlindnessMode colorBlindness)
where T : IImageProcessor<Rgba32> where T : IImageProcessor<Rgba32>
{ {
this.operations.ColorBlindness(colorBlindness); this.operations.ColorBlindness(colorBlindness);
@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Filters
} }
[Theory] [Theory]
[MemberData(nameof(TheoryData))] [MemberData(nameof(TheoryData))]
public void ColorBlindness_rect_CorrectProcessor<T>(TestType<T> testType, ColorBlindness colorBlindness) public void ColorBlindness_rect_CorrectProcessor<T>(TestType<T> testType, ColorBlindnessMode colorBlindness)
where T : IImageProcessor<Rgba32> where T : IImageProcessor<Rgba32>
{ {
this.operations.ColorBlindness(colorBlindness, this.rect); this.operations.ColorBlindness(colorBlindness, this.rect);

4
tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs

@ -16,14 +16,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Filters
[Fact] [Fact]
public void Filter_CorrectProcessor() public void Filter_CorrectProcessor()
{ {
this.operations.Filter(MatrixFilters.AchromatomalyFilter * MatrixFilters.CreateHueFilter(90F)); this.operations.Filter(KnownFilterMatrices.AchromatomalyFilter * KnownFilterMatrices.CreateHueFilter(90F));
FilterProcessor<Rgba32> p = this.Verify<FilterProcessor<Rgba32>>(); FilterProcessor<Rgba32> p = this.Verify<FilterProcessor<Rgba32>>();
} }
[Fact] [Fact]
public void Filter_rect_CorrectProcessor() public void Filter_rect_CorrectProcessor()
{ {
this.operations.Filter(MatrixFilters.AchromatomalyFilter * MatrixFilters.CreateHueFilter(90F), this.rect); this.operations.Filter(KnownFilterMatrices.AchromatomalyFilter * KnownFilterMatrices.CreateHueFilter(90F), this.rect);
FilterProcessor<Rgba32> p = this.Verify<FilterProcessor<Rgba32>>(this.rect); FilterProcessor<Rgba32> p = this.Verify<FilterProcessor<Rgba32>>(this.rect);
} }
} }

30
tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryDitherTests.cs

@ -25,29 +25,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
public static readonly TheoryData<string, IOrderedDither> OrderedDitherers = new TheoryData<string, IOrderedDither> public static readonly TheoryData<string, IOrderedDither> OrderedDitherers = new TheoryData<string, IOrderedDither>
{ {
{ "Bayer8x8", DitherMode.BayerDither8x8 }, { "Bayer8x8", KnownDitherers.BayerDither8x8 },
{ "Bayer4x4", DitherMode.BayerDither4x4 }, { "Bayer4x4", KnownDitherers.BayerDither4x4 },
{ "Ordered3x3", DitherMode.OrderedDither3x3 }, { "Ordered3x3", KnownDitherers.OrderedDither3x3 },
{ "Bayer2x2", DitherMode.BayerDither2x2 } { "Bayer2x2", KnownDitherers.BayerDither2x2 }
}; };
public static readonly TheoryData<string, IErrorDiffuser> ErrorDiffusers = new TheoryData<string, IErrorDiffuser> public static readonly TheoryData<string, IErrorDiffuser> ErrorDiffusers = new TheoryData<string, IErrorDiffuser>
{ {
{ "Atkinson", DiffuseMode.Atkinson }, { "Atkinson", KnownDiffusers.Atkinson },
{ "Burks", DiffuseMode.Burks }, { "Burks", KnownDiffusers.Burks },
{ "FloydSteinberg", DiffuseMode.FloydSteinberg }, { "FloydSteinberg", KnownDiffusers.FloydSteinberg },
{ "JarvisJudiceNinke", DiffuseMode.JarvisJudiceNinke }, { "JarvisJudiceNinke", KnownDiffusers.JarvisJudiceNinke },
{ "Sierra2", DiffuseMode.Sierra2 }, { "Sierra2", KnownDiffusers.Sierra2 },
{ "Sierra3", DiffuseMode.Sierra3 }, { "Sierra3", KnownDiffusers.Sierra3 },
{ "SierraLite", DiffuseMode.SierraLite }, { "SierraLite", KnownDiffusers.SierraLite },
{ "StevensonArce", DiffuseMode.StevensonArce }, { "StevensonArce", KnownDiffusers.StevensonArce },
{ "Stucki", DiffuseMode.Stucki }, { "Stucki", KnownDiffusers.Stucki },
}; };
private static IOrderedDither DefaultDitherer => DitherMode.BayerDither4x4; private static IOrderedDither DefaultDitherer => KnownDitherers.BayerDither4x4;
private static IErrorDiffuser DefaultErrorDiffuser => DiffuseMode.Atkinson; private static IErrorDiffuser DefaultErrorDiffuser => KnownDiffusers.Atkinson;
[Theory] [Theory]
[WithFileCollection(nameof(CommonTestImages), nameof(OrderedDitherers), DefaultPixelType)] [WithFileCollection(nameof(CommonTestImages), nameof(OrderedDitherers), DefaultPixelType)]

30
tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs

@ -24,29 +24,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
public static readonly TheoryData<string, IOrderedDither> OrderedDitherers = new TheoryData<string, IOrderedDither> public static readonly TheoryData<string, IOrderedDither> OrderedDitherers = new TheoryData<string, IOrderedDither>
{ {
{ "Bayer8x8", DitherMode.BayerDither8x8 }, { "Bayer8x8", KnownDitherers.BayerDither8x8 },
{ "Bayer4x4", DitherMode.BayerDither4x4 }, { "Bayer4x4", KnownDitherers.BayerDither4x4 },
{ "Ordered3x3", DitherMode.OrderedDither3x3 }, { "Ordered3x3", KnownDitherers.OrderedDither3x3 },
{ "Bayer2x2", DitherMode.BayerDither2x2 } { "Bayer2x2", KnownDitherers.BayerDither2x2 }
}; };
public static readonly TheoryData<string, IErrorDiffuser> ErrorDiffusers = new TheoryData<string, IErrorDiffuser> public static readonly TheoryData<string, IErrorDiffuser> ErrorDiffusers = new TheoryData<string, IErrorDiffuser>
{ {
{ "Atkinson", DiffuseMode.Atkinson }, { "Atkinson", KnownDiffusers.Atkinson },
{ "Burks", DiffuseMode.Burks }, { "Burks", KnownDiffusers.Burks },
{ "FloydSteinberg", DiffuseMode.FloydSteinberg }, { "FloydSteinberg", KnownDiffusers.FloydSteinberg },
{ "JarvisJudiceNinke", DiffuseMode.JarvisJudiceNinke }, { "JarvisJudiceNinke", KnownDiffusers.JarvisJudiceNinke },
{ "Sierra2", DiffuseMode.Sierra2 }, { "Sierra2", KnownDiffusers.Sierra2 },
{ "Sierra3", DiffuseMode.Sierra3 }, { "Sierra3", KnownDiffusers.Sierra3 },
{ "SierraLite", DiffuseMode.SierraLite }, { "SierraLite", KnownDiffusers.SierraLite },
{ "StevensonArce", DiffuseMode.StevensonArce }, { "StevensonArce", KnownDiffusers.StevensonArce },
{ "Stucki", DiffuseMode.Stucki }, { "Stucki", KnownDiffusers.Stucki },
}; };
private static IOrderedDither DefaultDitherer => DitherMode.BayerDither4x4; private static IOrderedDither DefaultDitherer => KnownDitherers.BayerDither4x4;
private static IErrorDiffuser DefaultErrorDiffuser => DiffuseMode.Atkinson; private static IErrorDiffuser DefaultErrorDiffuser => KnownDiffusers.Atkinson;
[Theory] [Theory]
[WithFileCollection(nameof(CommonTestImages), nameof(OrderedDitherers), DefaultPixelType)] [WithFileCollection(nameof(CommonTestImages), nameof(OrderedDitherers), DefaultPixelType)]

22
tests/ImageSharp.Tests/Processing/Processors/Filters/ColorBlindnessTest.cs

@ -13,22 +13,22 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Filters
[GroupOutput("Filters")] [GroupOutput("Filters")]
public class ColorBlindnessTest public class ColorBlindnessTest
{ {
public static readonly TheoryData<ColorBlindness> ColorBlindnessFilters public static readonly TheoryData<ColorBlindnessMode> ColorBlindnessFilters
= new TheoryData<ColorBlindness> = new TheoryData<ColorBlindnessMode>
{ {
ColorBlindness.Achromatomaly, ColorBlindnessMode.Achromatomaly,
ColorBlindness.Achromatopsia, ColorBlindnessMode.Achromatopsia,
ColorBlindness.Deuteranomaly, ColorBlindnessMode.Deuteranomaly,
ColorBlindness.Deuteranopia, ColorBlindnessMode.Deuteranopia,
ColorBlindness.Protanomaly, ColorBlindnessMode.Protanomaly,
ColorBlindness.Protanopia, ColorBlindnessMode.Protanopia,
ColorBlindness.Tritanomaly, ColorBlindnessMode.Tritanomaly,
ColorBlindness.Tritanopia ColorBlindnessMode.Tritanopia
}; };
[Theory] [Theory]
[WithTestPatternImages(nameof(ColorBlindnessFilters), 48, 48, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(ColorBlindnessFilters), 48, 48, PixelTypes.Rgba32)]
public void ApplyColorBlindnessFilter<TPixel>(TestImageProvider<TPixel> provider, ColorBlindness colorBlindness) public void ApplyColorBlindnessFilter<TPixel>(TestImageProvider<TPixel> provider, ColorBlindnessMode colorBlindness)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.RunValidatingProcessorTest(x => x.ColorBlindness(colorBlindness), colorBlindness.ToString()); provider.RunValidatingProcessorTest(x => x.ColorBlindness(colorBlindness), colorBlindness.ToString());

6
tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs

@ -40,9 +40,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Filters
private static Matrix4x4 CreateCombinedTestFilterMatrix() private static Matrix4x4 CreateCombinedTestFilterMatrix()
{ {
Matrix4x4 brightness = MatrixFilters.CreateBrightnessFilter(0.9F); Matrix4x4 brightness = KnownFilterMatrices.CreateBrightnessFilter(0.9F);
Matrix4x4 hue = MatrixFilters.CreateHueFilter(180F); Matrix4x4 hue = KnownFilterMatrices.CreateHueFilter(180F);
Matrix4x4 saturation = MatrixFilters.CreateSaturateFilter(1.5F); Matrix4x4 saturation = KnownFilterMatrices.CreateSaturateFilter(1.5F);
Matrix4x4 m = brightness * hue * saturation; Matrix4x4 m = brightness * hue * saturation;
return m; return m;
} }

24
tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs

@ -15,18 +15,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{ {
public static readonly string[] FlipFiles = { TestImages.Bmp.F }; public static readonly string[] FlipFiles = { TestImages.Bmp.F };
public static readonly TheoryData<RotateType, FlipType, ushort> OrientationValues public static readonly TheoryData<RotateMode, FlipMode, ushort> OrientationValues
= new TheoryData<RotateType, FlipType, ushort> = new TheoryData<RotateMode, FlipMode, ushort>
{ {
{ RotateType.None, FlipType.None, 0 }, { RotateMode.None, FlipMode.None, 0 },
{ RotateType.None, FlipType.None, 1 }, { RotateMode.None, FlipMode.None, 1 },
{ RotateType.None, FlipType.Horizontal, 2 }, { RotateMode.None, FlipMode.Horizontal, 2 },
{ RotateType.Rotate180, FlipType.None, 3 }, { RotateMode.Rotate180, FlipMode.None, 3 },
{ RotateType.Rotate180, FlipType.Horizontal, 4 }, { RotateMode.Rotate180, FlipMode.Horizontal, 4 },
{ RotateType.Rotate90, FlipType.Horizontal, 5 }, { RotateMode.Rotate90, FlipMode.Horizontal, 5 },
{ RotateType.Rotate270, FlipType.None, 6 }, { RotateMode.Rotate270, FlipMode.None, 6 },
{ RotateType.Rotate90, FlipType.Vertical, 7 }, { RotateMode.Rotate90, FlipMode.Vertical, 7 },
{ RotateType.Rotate90, FlipType.None, 8 }, { RotateMode.Rotate90, FlipMode.None, 8 },
}; };
public static readonly TheoryData<ExifDataType, byte[]> InvalidOrientationValues public static readonly TheoryData<ExifDataType, byte[]> InvalidOrientationValues
@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[Theory] [Theory]
[WithFileCollection(nameof(FlipFiles), nameof(OrientationValues), DefaultPixelType)] [WithFileCollection(nameof(FlipFiles), nameof(OrientationValues), DefaultPixelType)]
public void ImageShouldAutoRotate<TPixel>(TestImageProvider<TPixel> provider, RotateType rotateType, FlipType flipType, ushort orientation) public void ImageShouldAutoRotate<TPixel>(TestImageProvider<TPixel> provider, RotateMode rotateType, FlipMode flipType, ushort orientation)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using (Image<TPixel> image = provider.GetImage())

12
tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs

@ -13,17 +13,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{ {
public static readonly string[] FlipFiles = { TestImages.Bmp.F }; public static readonly string[] FlipFiles = { TestImages.Bmp.F };
public static readonly TheoryData<FlipType> FlipValues public static readonly TheoryData<FlipMode> FlipValues
= new TheoryData<FlipType> = new TheoryData<FlipMode>
{ {
{ FlipType.None }, { FlipMode.None },
{ FlipType.Vertical }, { FlipMode.Vertical },
{ FlipType.Horizontal }, { FlipMode.Horizontal },
}; };
[Theory] [Theory]
[WithFileCollection(nameof(FlipFiles), nameof(FlipValues), DefaultPixelType)] [WithFileCollection(nameof(FlipFiles), nameof(FlipValues), DefaultPixelType)]
public void ImageShouldFlip<TPixel>(TestImageProvider<TPixel> provider, FlipType flipType) public void ImageShouldFlip<TPixel>(TestImageProvider<TPixel> provider, FlipMode flipType)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using (Image<TPixel> image = provider.GetImage())

2
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs

@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public void PrintWeightsData() public void PrintWeightsData()
{ {
var size = new Size(500, 500); var size = new Size(500, 500);
var proc = new ResizeProcessor<Rgba32>(ResampleMode.Bicubic, 200, 200, size); var proc = new ResizeProcessor<Rgba32>(KnownResamplers.Bicubic, 200, 200, size);
WeightsBuffer weights = proc.PrecomputeWeights(Configuration.Default.MemoryManager, proc.Width, size.Width); WeightsBuffer weights = proc.PrecomputeWeights(Configuration.Default.MemoryManager, proc.Width, size.Width);

38
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -20,20 +20,20 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public static readonly TheoryData<string, IResampler> AllReSamplers = public static readonly TheoryData<string, IResampler> AllReSamplers =
new TheoryData<string, IResampler> new TheoryData<string, IResampler>
{ {
{ "Bicubic", ResampleMode.Bicubic }, { "Bicubic", KnownResamplers.Bicubic },
{ "Triangle", ResampleMode.Triangle}, { "Triangle", KnownResamplers.Triangle},
{ "NearestNeighbor", ResampleMode.NearestNeighbor }, { "NearestNeighbor", KnownResamplers.NearestNeighbor },
{ "Box", ResampleMode.Box }, { "Box", KnownResamplers.Box },
// { "Lanczos2", KnownResamplers.Lanczos2 }, TODO: Add expected file // { "Lanczos2", KnownResamplers.Lanczos2 }, TODO: Add expected file
{ "Lanczos3", ResampleMode.Lanczos3 }, { "Lanczos3", KnownResamplers.Lanczos3 },
{ "Lanczos5", ResampleMode.Lanczos5 }, { "Lanczos5", KnownResamplers.Lanczos5 },
{ "MitchellNetravali", ResampleMode.MitchellNetravali }, { "MitchellNetravali", KnownResamplers.MitchellNetravali },
{ "Lanczos8", ResampleMode.Lanczos8 }, { "Lanczos8", KnownResamplers.Lanczos8 },
{ "Hermite", ResampleMode.Hermite }, { "Hermite", KnownResamplers.Hermite },
{ "Spline", ResampleMode.Spline }, { "Spline", KnownResamplers.Spline },
{ "Robidoux", ResampleMode.Robidoux }, { "Robidoux", KnownResamplers.Robidoux },
{ "RobidouxSharp", ResampleMode.RobidouxSharp }, { "RobidouxSharp", KnownResamplers.RobidouxSharp },
{ "Welch", ResampleMode.Welch } { "Welch", KnownResamplers.Welch }
}; };
[Theory] [Theory]
@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{ {
using (Image<TPixel> image = provider.GetImage()) using (Image<TPixel> image = provider.GetImage())
{ {
image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, ResampleMode.NearestNeighbor)); image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, KnownResamplers.NearestNeighbor));
// Comparer fights decoder with gif-s. Could not use CompareToReferenceOutput here :( // Comparer fights decoder with gif-s. Could not use CompareToReferenceOutput here :(
image.DebugSave(provider, extension: Extensions.Gif); image.DebugSave(provider, extension: Extensions.Gif);
@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
var sourceRectangle = new Rectangle(image.Width / 8, image.Height / 8, image.Width / 4, image.Height / 4); var sourceRectangle = new Rectangle(image.Width / 8, image.Height / 8, image.Width / 4, image.Height / 4);
var destRectangle = new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2); var destRectangle = new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2);
image.Mutate(x => x.Resize(image.Width, image.Height, ResampleMode.Bicubic, sourceRectangle, destRectangle, false)); image.Mutate(x => x.Resize(image.Width, image.Height, KnownResamplers.Bicubic, sourceRectangle, destRectangle, false));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(provider); image.CompareToReferenceOutput(provider);
@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(2, 0)] [InlineData(2, 0)]
public static void BicubicWindowOscillatesCorrectly(float x, float expected) public static void BicubicWindowOscillatesCorrectly(float x, float expected)
{ {
var sampler = ResampleMode.Bicubic; var sampler = KnownResamplers.Bicubic;
float result = sampler.GetValue(x); float result = sampler.GetValue(x);
Assert.Equal(result, expected); Assert.Equal(result, expected);
@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(2, 0)] [InlineData(2, 0)]
public static void TriangleWindowOscillatesCorrectly(float x, float expected) public static void TriangleWindowOscillatesCorrectly(float x, float expected)
{ {
var sampler = ResampleMode.Triangle; var sampler = KnownResamplers.Triangle;
float result = sampler.GetValue(x); float result = sampler.GetValue(x);
Assert.Equal(result, expected); Assert.Equal(result, expected);
@ -328,7 +328,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(2, 0)] [InlineData(2, 0)]
public static void Lanczos3WindowOscillatesCorrectly(float x, float expected) public static void Lanczos3WindowOscillatesCorrectly(float x, float expected)
{ {
var sampler = ResampleMode.Lanczos3; var sampler = KnownResamplers.Lanczos3;
float result = sampler.GetValue(x); float result = sampler.GetValue(x);
Assert.Equal(result, expected); Assert.Equal(result, expected);
@ -342,7 +342,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(4, 0)] [InlineData(4, 0)]
public static void Lanczos5WindowOscillatesCorrectly(float x, float expected) public static void Lanczos5WindowOscillatesCorrectly(float x, float expected)
{ {
var sampler = ResampleMode.Lanczos5; var sampler = KnownResamplers.Lanczos5;
float result = sampler.GetValue(x); float result = sampler.GetValue(x);
Assert.Equal(result, expected); Assert.Equal(result, expected);

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

Loading…
Cancel
Save