Browse Source

Normalize MemoryAllocator references.

pull/1095/head
James Jackson-South 7 years ago
parent
commit
c690e0cf90
  1. 4
      src/ImageSharp/Advanced/AotCompilerTools.cs
  2. 2
      src/ImageSharp/Configuration.cs
  3. 2
      src/ImageSharp/Formats/Gif/GifEncoder.cs
  4. 23
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  5. 6
      src/ImageSharp/ImageFrame.cs
  6. 6
      src/ImageSharp/ImageFrame{TPixel}.cs
  7. 5
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
  8. 3
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  9. 3
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  10. 24
      src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs
  11. 10
      src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
  12. 8
      src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
  13. 5
      src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
  14. 4
      src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
  15. 40
      src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
  16. 9
      src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
  17. 2
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs
  18. 2
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

4
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileOctreeQuantizer<TPixel>() private static void AotCompileOctreeQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var test = new OctreeFrameQuantizer<TPixel>(new OctreeQuantizer(false))) using (var test = new OctreeFrameQuantizer<TPixel>(Configuration.Default, new OctreeQuantizer(false)))
{ {
test.AotGetPalette(); test.AotGetPalette();
} }
@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileWuQuantizer<TPixel>() private static void AotCompileWuQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var test = new WuFrameQuantizer<TPixel>(Configuration.Default.MemoryAllocator, new WuQuantizer(false))) using (var test = new WuFrameQuantizer<TPixel>(Configuration.Default, new WuQuantizer(false)))
{ {
test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1)); test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1));
test.AotGetPalette(); test.AotGetPalette();

2
src/ImageSharp/Configuration.cs

@ -16,7 +16,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
/// <summary> /// <summary>
/// Provides configuration code which allows altering default behaviour or extending the library. /// Provides configuration which allows altering default behaviour or extending the library.
/// </summary> /// </summary>
public sealed class Configuration public sealed class Configuration
{ {

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

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var encoder = new GifEncoderCore(image.GetConfiguration().MemoryAllocator, this); var encoder = new GifEncoderCore(image.GetConfiguration(), this);
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
} }

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

@ -53,11 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GifEncoderCore"/> class. /// Initializes a new instance of the <see cref="GifEncoderCore"/> class.
/// </summary> /// </summary>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="options">The options for the encoder.</param> /// <param name="options">The options for the encoder.</param>
public GifEncoderCore(MemoryAllocator memoryAllocator, IGifEncoderOptions options) public GifEncoderCore(Configuration configuration, IGifEncoderOptions options)
{ {
this.memoryAllocator = memoryAllocator; this.configuration = configuration;
this.memoryAllocator = configuration.MemoryAllocator;
this.quantizer = options.Quantizer; this.quantizer = options.Quantizer;
this.colorTableMode = options.ColorTableMode; this.colorTableMode = options.ColorTableMode;
} }
@ -74,16 +75,14 @@ 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.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata; ImageMetadata metadata = image.Metadata;
GifMetadata gifMetadata = metadata.GetGifMetadata(); GifMetadata gifMetadata = metadata.GetGifMetadata();
this.colorTableMode = this.colorTableMode ?? gifMetadata.ColorTableMode; this.colorTableMode ??= gifMetadata.ColorTableMode;
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
// Quantize the image returning a palette. // Quantize the image returning a palette.
IQuantizedFrame<TPixel> quantized; IQuantizedFrame<TPixel> quantized;
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())) using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration))
{ {
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame); quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
} }
@ -146,7 +145,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
else else
{ {
using (IFrameQuantizer<TPixel> paletteFrameQuantizer = using (IFrameQuantizer<TPixel> paletteFrameQuantizer =
new PaletteFrameQuantizer<TPixel>(this.quantizer.Diffuser, quantized.Palette)) new PaletteFrameQuantizer<TPixel>(this.configuration, this.quantizer.Diffuser, quantized.Palette))
{ {
using (IQuantizedFrame<TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame)) using (IQuantizedFrame<TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame))
{ {
@ -172,14 +171,14 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength
&& frameMetadata.ColorTableLength > 0) && frameMetadata.ColorTableLength > 0)
{ {
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration(), frameMetadata.ColorTableLength)) using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration, frameMetadata.ColorTableLength))
{ {
quantized = frameQuantizer.QuantizeFrame(frame); quantized = frameQuantizer.QuantizeFrame(frame);
} }
} }
else else
{ {
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())) using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration))
{ {
quantized = frameQuantizer.QuantizeFrame(frame); quantized = frameQuantizer.QuantizeFrame(frame);
} }
@ -202,9 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Returns the index of the most transparent color in the palette. /// Returns the index of the most transparent color in the palette.
/// </summary> /// </summary>
/// <param name="quantized"> /// <param name="quantized">The quantized frame.</param>
/// The quantized.
/// </param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns> /// <returns>
/// The <see cref="int"/>. /// The <see cref="int"/>.

6
src/ImageSharp/ImageFrame.cs

@ -31,17 +31,11 @@ namespace SixLabors.ImageSharp
Guard.NotNull(metadata, nameof(metadata)); Guard.NotNull(metadata, nameof(metadata));
this.configuration = configuration ?? Configuration.Default; this.configuration = configuration ?? Configuration.Default;
this.MemoryAllocator = configuration.MemoryAllocator;
this.Width = width; this.Width = width;
this.Height = height; this.Height = height;
this.Metadata = metadata; this.Metadata = metadata;
} }
/// <summary>
/// Gets the <see cref="MemoryAllocator" /> to use for buffer allocations.
/// </summary>
public MemoryAllocator MemoryAllocator { get; }
/// <summary> /// <summary>
/// Gets the width. /// Gets the width.
/// </summary> /// </summary>

6
src/ImageSharp/ImageFrame{TPixel}.cs

@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.MustBeGreaterThan(height, 0, nameof(height));
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(width, height, AllocationOptions.Clean); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D<TPixel>(width, height, AllocationOptions.Clean);
} }
/// <summary> /// <summary>
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.MustBeGreaterThan(height, 0, nameof(height));
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(width, height); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D<TPixel>(width, height);
this.Clear(backgroundColor); this.Clear(backgroundColor);
} }
@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(source, nameof(source)); Guard.NotNull(source, nameof(source));
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan());
} }

5
src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs

@ -65,9 +65,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
Configuration configuration = this.Configuration; Configuration configuration = this.Configuration;
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (IMemoryOwner<TPixel> colors = source.MemoryAllocator.Allocate<TPixel>(width)) using (IMemoryOwner<TPixel> colors = memoryAllocator.Allocate<TPixel>(width))
using (IMemoryOwner<float> amount = source.MemoryAllocator.Allocate<float>(width)) using (IMemoryOwner<float> amount = memoryAllocator.Allocate<float>(width))
{ {
// Be careful! Do not capture colorSpan & amountSpan in the lambda below! // Be careful! Do not capture colorSpan & amountSpan in the lambda below!
Span<TPixel> colorSpan = colors.GetSpan(); Span<TPixel> colorSpan = colors.GetSpan();

3
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs

@ -77,8 +77,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
float blendPercentage = this.definition.GraphicsOptions.BlendPercentage; float blendPercentage = this.definition.GraphicsOptions.BlendPercentage;
Configuration configuration = this.Configuration; Configuration configuration = this.Configuration;
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (IMemoryOwner<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width)) using (IMemoryOwner<TPixel> rowColors = memoryAllocator.Allocate<TPixel>(width))
{ {
rowColors.GetSpan().Fill(glowColor); rowColors.GetSpan().Fill(glowColor);

3
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs

@ -81,8 +81,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
float blendPercentage = this.definition.GraphicsOptions.BlendPercentage; float blendPercentage = this.definition.GraphicsOptions.BlendPercentage;
Configuration configuration = this.Configuration; Configuration configuration = this.Configuration;
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (IMemoryOwner<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width)) using (IMemoryOwner<TPixel> rowColors = memoryAllocator.Allocate<TPixel>(width))
{ {
rowColors.GetSpan().Fill(vignetteColor); rowColors.GetSpan().Fill(vignetteColor);

24
src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs

@ -7,7 +7,7 @@ using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Dithering;
@ -40,6 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="FrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="quantizer">The quantizer</param> /// <param name="quantizer">The quantizer</param>
/// <param name="singlePass"> /// <param name="singlePass">
/// If true, the quantization process only needs to loop through the source pixels once /// If true, the quantization process only needs to loop through the source pixels once
@ -49,10 +50,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// only call the <see cref="SecondPass(ImageFrame{TPixel}, Span{byte}, ReadOnlySpan{TPixel}, int, int)"/> method. /// only call the <see cref="SecondPass(ImageFrame{TPixel}, Span{byte}, ReadOnlySpan{TPixel}, int, int)"/> method.
/// If two passes are required, the code will also call <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/>. /// If two passes are required, the code will also call <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/>.
/// </remarks> /// </remarks>
protected FrameQuantizer(IQuantizer quantizer, bool singlePass) protected FrameQuantizer(Configuration configuration, IQuantizer quantizer, bool singlePass)
{ {
Guard.NotNull(quantizer, nameof(quantizer)); Guard.NotNull(quantizer, nameof(quantizer));
this.Configuration = configuration;
this.Diffuser = quantizer.Diffuser; this.Diffuser = quantizer.Diffuser;
this.Dither = this.Diffuser != null; this.Dither = this.Diffuser != null;
this.singlePass = singlePass; this.singlePass = singlePass;
@ -61,6 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="FrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="diffuser">The diffuser</param> /// <param name="diffuser">The diffuser</param>
/// <param name="singlePass"> /// <param name="singlePass">
/// If true, the quantization process only needs to loop through the source pixels once /// If true, the quantization process only needs to loop through the source pixels once
@ -70,8 +73,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// only call the <see cref="SecondPass(ImageFrame{TPixel}, Span{byte}, ReadOnlySpan{TPixel}, int, int)"/> method. /// only call the <see cref="SecondPass(ImageFrame{TPixel}, Span{byte}, ReadOnlySpan{TPixel}, int, int)"/> method.
/// If two passes are required, the code will also call <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/>. /// If two passes are required, the code will also call <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/>.
/// </remarks> /// </remarks>
protected FrameQuantizer(IErrorDiffuser diffuser, bool singlePass) protected FrameQuantizer(Configuration configuration, IErrorDiffuser diffuser, bool singlePass)
{ {
this.Configuration = configuration;
this.Diffuser = diffuser; this.Diffuser = diffuser;
this.Dither = this.Diffuser != null; this.Dither = this.Diffuser != null;
this.singlePass = singlePass; this.singlePass = singlePass;
@ -83,6 +87,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <inheritdoc /> /// <inheritdoc />
public bool Dither { get; } public bool Dither { get; }
/// <summary>
/// Gets the configuration which allows altering default behaviour or extending the library.
/// </summary>
protected Configuration Configuration { get; }
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {
@ -109,15 +118,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
// Collect the palette. Required before the second pass runs. // Collect the palette. Required before the second pass runs.
ReadOnlyMemory<TPixel> palette = this.GetPalette(); ReadOnlyMemory<TPixel> palette = this.GetPalette();
Configuration configuration = image.GetConfiguration(); MemoryAllocator memoryAllocator = this.Configuration.MemoryAllocator;
this.paletteVector = configuration.MemoryAllocator.Allocate<Vector4>(palette.Length);
this.paletteVector = memoryAllocator.Allocate<Vector4>(palette.Length);
PixelOperations<TPixel>.Instance.ToVector4( PixelOperations<TPixel>.Instance.ToVector4(
configuration, this.Configuration,
palette.Span, palette.Span,
this.paletteVector.Memory.Span, this.paletteVector.Memory.Span,
PixelConversionModifiers.Scale); PixelConversionModifiers.Scale);
var quantizedFrame = new QuantizedFrame<TPixel>(image.MemoryAllocator, width, height, palette); var quantizedFrame = new QuantizedFrame<TPixel>(memoryAllocator, width, height, palette);
Span<byte> pixelSpan = quantizedFrame.GetWritablePixelSpan(); Span<byte> pixelSpan = quantizedFrame.GetWritablePixelSpan();
if (this.Dither) if (this.Dither)

10
src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs

@ -37,27 +37,29 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="OctreeFrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="OctreeFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="quantizer">The octree quantizer</param> /// <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 OctreeFrameQuantizer(OctreeQuantizer quantizer) public OctreeFrameQuantizer(Configuration configuration, OctreeQuantizer quantizer)
: this(quantizer, quantizer.MaxColors) : this(configuration, quantizer, quantizer.MaxColors)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="OctreeFrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="OctreeFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="quantizer">The octree quantizer.</param> /// <param name="quantizer">The octree quantizer.</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette.</param> /// <param name="maxColors">The maximum number of colors to hold in the color palette.</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 OctreeFrameQuantizer(OctreeQuantizer quantizer, int maxColors) public OctreeFrameQuantizer(Configuration configuration, OctreeQuantizer quantizer, int maxColors)
: base(quantizer, false) : base(configuration, quantizer, false)
{ {
this.colors = maxColors; this.colors = maxColors;
this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.colors).Clamp(1, 8)); this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.colors).Clamp(1, 8));

8
src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs

@ -1,4 +1,4 @@
// 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 SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -83,16 +83,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <inheritdoc /> /// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration) public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> new OctreeFrameQuantizer<TPixel>(this); => new OctreeFrameQuantizer<TPixel>(configuration, this);
/// <inheritdoc/> /// <inheritdoc/>
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors) public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
return new OctreeFrameQuantizer<TPixel>(this, maxColors); return new OctreeFrameQuantizer<TPixel>(configuration, this, maxColors);
} }
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
} }
} }

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

@ -26,10 +26,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PaletteFrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="PaletteFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="diffuser">The palette quantizer.</param> /// <param name="diffuser">The palette quantizer.</param>
/// <param name="colors">An array of all colors in the palette.</param> /// <param name="colors">An array of all colors in the palette.</param>
public PaletteFrameQuantizer(IErrorDiffuser diffuser, ReadOnlyMemory<TPixel> colors) public PaletteFrameQuantizer(Configuration configuration, IErrorDiffuser diffuser, ReadOnlyMemory<TPixel> colors)
: base(diffuser, true) => this.palette = colors; : base(configuration, diffuser, true) => this.palette = colors;
/// <inheritdoc/> /// <inheritdoc/>
protected override void SecondPass( protected override void SecondPass(

4
src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{ {
var palette = new TPixel[this.Palette.Length]; var palette = new TPixel[this.Palette.Length];
Color.ToPixel(configuration, this.Palette.Span, palette.AsSpan()); Color.ToPixel(configuration, this.Palette.Span, palette.AsSpan());
return new PaletteFrameQuantizer<TPixel>(this.Diffuser, palette); return new PaletteFrameQuantizer<TPixel>(configuration, this.Diffuser, palette);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
var palette = new TPixel[max]; var palette = new TPixel[max];
Color.ToPixel(configuration, this.Palette.Span.Slice(0, max), palette.AsSpan()); Color.ToPixel(configuration, this.Palette.Span.Slice(0, max), palette.AsSpan());
return new PaletteFrameQuantizer<TPixel>(this.Diffuser, palette); return new PaletteFrameQuantizer<TPixel>(configuration, this.Diffuser, palette);
} }
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;

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

@ -37,6 +37,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
internal sealed class WuFrameQuantizer<TPixel> : FrameQuantizer<TPixel> internal sealed class WuFrameQuantizer<TPixel> : FrameQuantizer<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private readonly MemoryAllocator memoryAllocator;
// The following two variables determine the amount of bits to preserve when calculating the histogram. // The following two variables determine the amount of bits to preserve when calculating the histogram.
// Reducing the value of these numbers the granularity of the color maps produced, making it much faster // Reducing the value of these numbers the granularity of the color maps produced, making it much faster
// and using much less memory but potentially less accurate. Current results are very good though! // and using much less memory but potentially less accurate. Current results are very good though!
@ -121,39 +123,39 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WuFrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="WuFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/>.</param> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="quantizer">The wu quantizer</param> /// <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 WuFrameQuantizer(MemoryAllocator memoryAllocator, WuQuantizer quantizer) public WuFrameQuantizer(Configuration configuration, WuQuantizer quantizer)
: this(memoryAllocator, quantizer, quantizer.MaxColors) : this(configuration, quantizer, quantizer.MaxColors)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WuFrameQuantizer{TPixel}"/> class. /// Initializes a new instance of the <see cref="WuFrameQuantizer{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/>.</param> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="quantizer">The wu quantizer.</param> /// <param name="quantizer">The Wu quantizer.</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette.</param> /// <param name="maxColors">The maximum number of colors to hold in the color palette.</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 WuFrameQuantizer(MemoryAllocator memoryAllocator, WuQuantizer quantizer, int maxColors) public WuFrameQuantizer(Configuration configuration, WuQuantizer quantizer, int maxColors)
: base(quantizer, false) : base(configuration, quantizer, false)
{ {
Guard.NotNull(memoryAllocator, nameof(memoryAllocator)); this.memoryAllocator = this.Configuration.MemoryAllocator;
this.vwt = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean); this.vwt = this.memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmr = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean); this.vmr = this.memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmg = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean); this.vmg = this.memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vmb = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean); this.vmb = this.memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.vma = memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean); this.vma = this.memoryAllocator.Allocate<long>(TableLength, AllocationOptions.Clean);
this.m2 = memoryAllocator.Allocate<double>(TableLength, AllocationOptions.Clean); this.m2 = this.memoryAllocator.Allocate<double>(TableLength, AllocationOptions.Clean);
this.tag = memoryAllocator.Allocate<byte>(TableLength, AllocationOptions.Clean); this.tag = this.memoryAllocator.Allocate<byte>(TableLength, AllocationOptions.Clean);
this.colors = maxColors; this.colors = maxColors;
} }
@ -229,7 +231,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
protected override void FirstPass(ImageFrame<TPixel> source, int width, int height) protected override void FirstPass(ImageFrame<TPixel> source, int width, int height)
{ {
this.Build3DHistogram(source, width, height); this.Build3DHistogram(source, width, height);
this.Get3DMoments(source.MemoryAllocator); this.Get3DMoments(this.memoryAllocator);
this.BuildCube(); this.BuildCube();
} }
@ -465,7 +467,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
// Build up the 3-D color histogram // Build up the 3-D color histogram
// Loop through each row // Loop through each row
using (IMemoryOwner<Rgba32> rgbaBuffer = source.MemoryAllocator.Allocate<Rgba32>(source.Width)) using (IMemoryOwner<Rgba32> rgbaBuffer = this.memoryAllocator.Allocate<Rgba32>(source.Width))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -840,7 +842,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
private void BuildCube() private void BuildCube()
{ {
this.colorCube = new Box[this.colors]; this.colorCube = new Box[this.colors];
var vv = new double[this.colors]; Span<double> vv = stackalloc double[this.colors];
ref Box cube = ref this.colorCube[0]; ref Box cube = ref this.colorCube[0];
cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0; cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0;

9
src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs

@ -1,4 +1,4 @@
// 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 SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -68,13 +68,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary> /// </summary>
public int MaxColors { get; } public int MaxColors { get; }
/// <param name="configuration"></param>
/// <inheritdoc /> /// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration) public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(configuration, nameof(configuration));
return new WuFrameQuantizer<TPixel>(configuration.MemoryAllocator, this); return new WuFrameQuantizer<TPixel>(configuration, this);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -83,9 +82,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{ {
Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(configuration, nameof(configuration));
maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
return new WuFrameQuantizer<TPixel>(configuration.MemoryAllocator, this, maxColors); return new WuFrameQuantizer<TPixel>(configuration, this, maxColors);
} }
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
} }
} }

2
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
var bBuffer = new Rgba64[width]; var bBuffer = new Rgba64[width];
var differences = new List<PixelDifference>(); var differences = new List<PixelDifference>();
Configuration configuration = expected.Configuration; Configuration configuration = expected.GetConfiguration();
for (int y = 0; y < actual.Height; y++) for (int y = 0; y < actual.Height; y++)
{ {

2
tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
float totalDifference = 0F; float totalDifference = 0F;
var differences = new List<PixelDifference>(); var differences = new List<PixelDifference>();
Configuration configuration = expected.Configuration; Configuration configuration = expected.GetConfiguration();
for (int y = 0; y < actual.Height; y++) for (int y = 0; y < actual.Height; y++)
{ {

Loading…
Cancel
Save