diff --git a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs
index d6dade770..1b0f8ad09 100644
--- a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs
@@ -137,17 +137,6 @@ namespace SixLabors.ImageSharp
return value;
}
- ///
- /// Converts an to a first restricting the value between the
- /// minimum and maximum allowable ranges.
- ///
- /// The this method extends.
- /// The
- public static byte ToByte(this int value)
- {
- return (byte)value.Clamp(0, 255);
- }
-
///
/// Converts an to a first restricting the value between the
/// minimum and maximum allowable ranges.
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 7837c2da5..928192701 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Png
where TPixel : struct, IPixel
{
var metaData = new ImageMetaData();
- var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance);
+ PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance);
this.currentStream = stream;
this.currentStream.Skip(8);
Image image = null;
@@ -307,7 +307,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public IImageInfo Identify(Stream stream)
{
var metaData = new ImageMetaData();
- var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance);
+ PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance);
this.currentStream = stream;
this.currentStream.Skip(8);
try
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 0b47c1c63..e4d2fc510 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -243,7 +243,7 @@ namespace SixLabors.ImageSharp.Formats.Png
// Collect the indexed pixel data
if (quantized != null)
{
- this.WritePaletteChunk(stream, header, quantized);
+ this.WritePaletteChunk(stream, quantized);
}
this.WritePhysicalChunk(stream, metaData);
@@ -555,30 +555,27 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// The pixel format.
/// The containing image data.
- /// The .
/// The quantized frame.
- private void WritePaletteChunk(Stream stream, in PngHeader header, QuantizedFrame quantized)
+ private void WritePaletteChunk(Stream stream, QuantizedFrame quantized)
where TPixel : struct, IPixel
{
// Grab the palette and write it to the stream.
TPixel[] palette = quantized.Palette;
- byte pixelCount = palette.Length.ToByte();
-
- // Get max colors for bit depth.
- int colorTableLength = ImageMaths.GetColorCountForBitDepth(header.BitDepth) * 3;
+ int paletteLength = Math.Min(palette.Length, 256);
+ int colorTableLength = paletteLength * 3;
Rgba32 rgba = default;
bool anyAlpha = false;
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
- using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(pixelCount))
+ using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength))
{
Span colorTableSpan = colorTable.GetSpan();
Span alphaTableSpan = alphaTable.GetSpan();
Span quantizedSpan = quantized.GetPixelSpan();
- for (byte i = 0; i < pixelCount; i++)
+ for (int i = 0; i < paletteLength; i++)
{
- if (quantizedSpan.IndexOf(i) > -1)
+ if (quantizedSpan.IndexOf((byte)i) > -1)
{
int offset = i * 3;
palette[i].ToRgba32(ref rgba);
@@ -604,7 +601,7 @@ namespace SixLabors.ImageSharp.Formats.Png
// Write the transparency data
if (anyAlpha)
{
- this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, pixelCount);
+ this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
index d71221b9d..5cd3d53ea 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
@@ -46,12 +46,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// The index bits.
///
- private const int IndexBits = 6;
+ private const int IndexBits = 5;
///
/// The index alpha bits.
///
- private const int IndexAlphaBits = 3;
+ private const int IndexAlphaBits = 5;
///
/// The index count.
@@ -201,57 +201,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
return this.palette;
}
- ///
- /// Quantizes the pixel
- ///
- /// The rgba used to quantize the pixel input
- private void QuantizePixel(ref Rgba32 rgba)
- {
- // Add the color to a 3-D color histogram.
- int r = rgba.R >> (8 - IndexBits);
- int g = rgba.G >> (8 - IndexBits);
- int b = rgba.B >> (8 - IndexBits);
- int a = rgba.A >> (8 - IndexAlphaBits);
-
- int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
-
- Span vwtSpan = this.vwt.GetSpan();
- Span vmrSpan = this.vmr.GetSpan();
- Span vmgSpan = this.vmg.GetSpan();
- Span vmbSpan = this.vmb.GetSpan();
- Span vmaSpan = this.vma.GetSpan();
- Span m2Span = this.m2.GetSpan();
-
- vwtSpan[index]++;
- vmrSpan[index] += rgba.R;
- vmgSpan[index] += rgba.G;
- vmbSpan[index] += rgba.B;
- vmaSpan[index] += rgba.A;
-
- var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A);
- m2Span[index] += Vector4.Dot(vector, vector);
- }
-
///
protected override void FirstPass(ImageFrame source, int width, int height)
{
- // Build up the 3-D color histogram
- // Loop through each row
- for (int y = 0; y < height; y++)
- {
- Span row = source.GetPixelRowSpan(y);
- ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row);
-
- // And loop through each column
- Rgba32 rgba = default;
- for (int x = 0; x < width; x++)
- {
- ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x);
- pixel.ToRgba32(ref rgba);
- this.QuantizePixel(ref rgba);
- }
- }
-
+ this.Build3DHistogram(source, width, height);
this.Get3DMoments(source.MemoryAllocator);
this.BuildCube();
}
@@ -466,6 +419,54 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
}
+ ///
+ /// Builds a 3-D color histogram of counts, r/g/b, c^2.
+ ///
+ /// The source data.
+ /// The width in pixels of the image.
+ /// The height in pixels of the image.
+ private void Build3DHistogram(ImageFrame source, int width, int height)
+ {
+ // Build up the 3-D color histogram
+ // Loop through each row
+ Span vwtSpan = this.vwt.GetSpan();
+ Span vmrSpan = this.vmr.GetSpan();
+ Span vmgSpan = this.vmg.GetSpan();
+ Span vmbSpan = this.vmb.GetSpan();
+ Span vmaSpan = this.vma.GetSpan();
+ Span m2Span = this.m2.GetSpan();
+
+ for (int y = 0; y < height; y++)
+ {
+ Span row = source.GetPixelRowSpan(y);
+ ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row);
+
+ // And loop through each column
+ Rgba32 rgba = default;
+ for (int x = 0; x < width; x++)
+ {
+ ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x);
+ pixel.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);
+
+ int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
+
+ vwtSpan[index]++;
+ vmrSpan[index] += rgba.R;
+ vmgSpan[index] += rgba.G;
+ vmbSpan[index] += rgba.B;
+ vmaSpan[index] += rgba.A;
+
+ var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A);
+ m2Span[index] += Vector4.Dot(vector, vector);
+ }
+ }
+ }
+
///
/// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box.
///