diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
index 2649b7fb16..89aca914d0 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
@@ -18,12 +18,12 @@ namespace SixLabors.ImageSharp.Memory
/// Gets the number of elements per contiguous sub-buffer preceding the last buffer.
/// The last buffer is allowed to be smaller.
///
- public int BufferLength { get; }
+ int BufferLength { get; }
///
/// Gets the aggregate number of elements in the group.
///
- public long TotalLength { get; }
+ long TotalLength { get; }
///
/// Gets a value indicating whether the group has been invalidated.
diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
index 9217d1c3f7..6aa6eeca69 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
@@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
for (int x = bounds.Left; x < bounds.Right; x++)
{
TPixel sourcePixel = row[x];
- TPixel transformed = processor.GetPaletteColor(sourcePixel, palette);
+ TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel, palette);
this.Dither(source, bounds, sourcePixel, transformed, x, y, scale);
row[x] = transformed;
}
diff --git a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs
index 3e4bf4d836..a890e929dc 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs
@@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
where TPixel : unmanaged, IPixel
{
///
- /// Gets the configration instance to use when performing operations.
+ /// Gets the configuration instance to use when performing operations.
///
- public Configuration Configuration { get; }
+ Configuration Configuration { get; }
///
/// Gets the dithering palette.
diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs
index d3e7107826..f6026a64f7 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs
@@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
///
/// An ordered dithering matrix with equal sides of arbitrary length
///
- public readonly partial struct OrderedDither : IDither
+ public readonly partial struct OrderedDither
{
///
/// Applies order dithering using the 2x2 Bayer dithering matrix.
diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
index c5b4135f56..9e97fe7e65 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
@@ -237,7 +237,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
for (int x = this.bounds.Left; x < this.bounds.Right; x++)
{
TPixel dithered = this.dither.Dither(sourceRow[x], x, y, this.bitDepth, scale);
- destinationRow[x - offsetX] = this.quantizer.GetQuantizedColor(dithered, paletteSpan, out TPixel _);
+ destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(dithered, paletteSpan, out TPixel _);
}
}
}
@@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
ref TPixel sourcePixel = ref row[x];
TPixel dithered = this.dither.Dither(sourcePixel, x, y, this.bitDepth, this.scale);
- sourcePixel = this.processor.GetPaletteColor(dithered, paletteSpan);
+ sourcePixel = Unsafe.AsRef(this.processor).GetPaletteColor(dithered, paletteSpan);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs
index d25048a7f7..4d4ccf1ab4 100644
--- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs
@@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
float ditherScale)
{
this.Configuration = configuration;
- this.pixelMap = new EuclideanPixelMap(palette);
+ this.pixelMap = new EuclideanPixelMap(configuration, palette);
this.Palette = palette;
this.DitherScale = ditherScale;
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs
index 615a7238b8..7147886297 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Concurrent;
using System.Numerics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
@@ -17,27 +18,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
internal readonly struct EuclideanPixelMap : IPixelMap, IEquatable>
where TPixel : unmanaged, IPixel
{
- private readonly ConcurrentDictionary vectorCache;
+ private readonly Vector4[] vectorCache;
private readonly ConcurrentDictionary distanceCache;
///
/// Initializes a new instance of the struct.
///
+ /// The configuration.
/// The color palette to map from.
[MethodImpl(InliningOptions.ShortMethod)]
- public EuclideanPixelMap(ReadOnlyMemory palette)
+ public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory palette)
{
Guard.MustBeGreaterThan(palette.Length, 0, nameof(palette));
this.Palette = palette;
ReadOnlySpan paletteSpan = this.Palette.Span;
- this.vectorCache = new ConcurrentDictionary();
+ this.vectorCache = new Vector4[paletteSpan.Length];
this.distanceCache = new ConcurrentDictionary();
- for (int i = 0; i < paletteSpan.Length; i++)
- {
- this.vectorCache[i] = paletteSpan[i].ToScaledVector4();
- }
+ PixelOperations.Instance.ToVector4(configuration, paletteSpan, this.vectorCache);
}
///
@@ -81,31 +80,32 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
int index = 0;
float leastDistance = float.MaxValue;
Vector4 vector = color.ToScaledVector4();
+ ref TPixel paletteRef = ref MemoryMarshal.GetReference(palette);
+ ref Vector4 vectorCacheRef = ref MemoryMarshal.GetReference(this.vectorCache);
for (int i = 0; i < palette.Length; i++)
{
- Vector4 candidate = this.vectorCache[i];
+ Vector4 candidate = Unsafe.Add(ref vectorCacheRef, i);
float distance = Vector4.DistanceSquared(vector, candidate);
- if (!(distance < leastDistance))
+ // If it's an exact match, exit the loop
+ if (distance == 0)
{
- continue;
+ index = i;
+ break;
}
- // Less than... assign.
- index = i;
- leastDistance = distance;
-
- // And if it's an exact match, exit the loop
- if (distance == 0)
+ if (distance < leastDistance)
{
- break;
+ // Less than... assign.
+ index = i;
+ leastDistance = distance;
}
}
// Now I have the index, pop it into the cache for next time
this.distanceCache[color] = index;
- match = palette[index];
+ match = Unsafe.Add(ref paletteRef, index);
return index;
}
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs
index d6d8b98dae..ef97f57e3d 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs
@@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
for (int x = this.bounds.Left; x < this.bounds.Right; x++)
{
- destinationRow[x - offsetX] = this.quantizer.GetQuantizedColor(sourceRow[x], paletteSpan, out TPixel _);
+ destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(sourceRow[x], paletteSpan, out TPixel _);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
index 946ae399bb..e80449b09f 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
@@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.octree.Palletize(paletteSpan, this.colors);
// TODO: Cannot make method readonly due to this line.
- this.pixelMap = new EuclideanPixelMap(this.palette.Memory);
+ this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory);
return paletteSpan;
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
index 3328fd6c7c..9e04edef0b 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
@@ -11,12 +11,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class OctreeQuantizer : IQuantizer
{
+ private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
+
///
/// Initializes a new instance of the class
/// using the default .
///
public OctreeQuantizer()
- : this(new QuantizerOptions())
+ : this(DefaultOptions)
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
index 7960f728af..3dbf77a3a9 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength);
Color.ToPixel(configuration, colors, this.paletteOwner.GetSpan());
- this.pixelMap = new EuclideanPixelMap(this.paletteOwner.Memory);
+ this.pixelMap = new EuclideanPixelMap(configuration, this.paletteOwner.Memory);
this.isDisposed = false;
}
@@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength);
palette.CopyTo(this.paletteOwner.GetSpan());
- this.pixelMap = new EuclideanPixelMap(this.paletteOwner.Memory);
+ this.pixelMap = new EuclideanPixelMap(configuration, this.paletteOwner.Memory);
this.isDisposed = false;
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
index 75a0f39389..e95f8c5db5 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
@@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class PaletteQuantizer : IQuantizer
{
+ private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
private readonly ReadOnlyMemory palette;
///
@@ -18,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// The color palette.
public PaletteQuantizer(ReadOnlyMemory palette)
- : this(palette, new QuantizerOptions())
+ : this(palette, DefaultOptions)
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
index 8aa634b9ff..d95ed5aab9 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
@@ -10,11 +10,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WebSafePaletteQuantizer : PaletteQuantizer
{
+ private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
+
///
/// Initializes a new instance of the class.
///
public WebSafePaletteQuantizer()
- : this(new QuantizerOptions())
+ : this(DefaultOptions)
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
index 168c837d57..8f8e38dd9d 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
@@ -9,11 +9,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WernerPaletteQuantizer : PaletteQuantizer
{
+ private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
+
///
/// Initializes a new instance of the class.
///
public WernerPaletteQuantizer()
- : this(new QuantizerOptions())
+ : this(DefaultOptions)
{
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
index 5054772582..6f98ce121e 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
@@ -132,30 +132,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
// TODO: Cannot make methods readonly due to this line.
- this.pixelMap = new EuclideanPixelMap(this.palette.Memory);
+ this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory);
return paletteSpan;
}
///
public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match)
{
- if (!this.isDithering)
+ if (this.isDithering)
{
- Rgba32 rgba = default;
- color.ToRgba32(ref rgba);
-
- int r = rgba.R >> (8 - IndexBits);
- int g = rgba.G >> (8 - IndexBits);
- int b = rgba.B >> (8 - IndexBits);
- int a = rgba.A >> (8 - IndexAlphaBits);
-
- ReadOnlySpan tagSpan = this.tag.GetSpan();
- byte index = tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)];
- match = palette[index];
- return index;
+ return (byte)this.pixelMap.GetClosestColor(color, out match);
}
- return (byte)this.pixelMap.GetClosestColor(color, out match);
+ Rgba32 rgba = default;
+ color.ToRgba32(ref rgba);
+
+ int r = rgba.R >> (8 - IndexBits);
+ int g = rgba.G >> (8 - IndexBits);
+ int b = rgba.B >> (8 - IndexBits);
+ int a = rgba.A >> (8 - IndexAlphaBits);
+
+ ReadOnlySpan tagSpan = this.tag.GetSpan();
+ byte index = tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)];
+ match = palette[index];
+ return index;
}
///
@@ -376,11 +376,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box.
///
- /// The memory allocator used for allocating buffers.
- private void Get3DMoments(MemoryAllocator memoryAllocator)
+ /// The memory allocator used for allocating buffers.
+ private void Get3DMoments(MemoryAllocator allocator)
{
- using IMemoryOwner volume = memoryAllocator.Allocate(IndexCount * IndexAlphaCount);
- using IMemoryOwner area = memoryAllocator.Allocate(IndexAlphaCount);
+ using IMemoryOwner volume = allocator.Allocate(IndexCount * IndexAlphaCount);
+ using IMemoryOwner area = allocator.Allocate(IndexAlphaCount);
Span momentSpan = this.moments.GetSpan();
Span volumeSpan = volume.GetSpan();
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
index 872e6d5bd4..d2e33aa1f1 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
@@ -10,12 +10,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WuQuantizer : IQuantizer
{
+ private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions();
+
///
/// Initializes a new instance of the class
/// using the default .
///
public WuQuantizer()
- : this(new QuantizerOptions())
+ : this(DefaultOptions)
{
}