Skip to content

Commit 45edceb

Browse files
Use more accuracy when calculating variance. Fix #866 (#874)
* Use more accuracy when calculating variance. Fix #866 * Add unit tests * Add test that fails with old image. * Make IFrameQuantizer IDisposable * Update GifEncoderCore.cs
1 parent cb18952 commit 45edceb

File tree

9 files changed

+422
-204
lines changed

9 files changed

+422
-204
lines changed

src/ImageSharp/Formats/Gif/GifEncoderCore.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,11 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
9595
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
9696

9797
// Quantize the image returning a palette.
98-
QuantizedFrame<TPixel> quantized =
99-
this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame);
98+
QuantizedFrame<TPixel> quantized = null;
99+
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
100+
{
101+
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
102+
}
100103

101104
// Get the number of bits.
102105
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
@@ -133,7 +136,6 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
133136

134137
// Clean up.
135138
quantized?.Dispose();
136-
quantized = null;
137139

138140
// TODO: Write extension etc
139141
stream.WriteByte(GifConstants.EndIntroducer);
@@ -158,7 +160,8 @@ private void EncodeGlobal<TPixel>(Image<TPixel> image, QuantizedFrame<TPixel> qu
158160
}
159161
else
160162
{
161-
using (QuantizedFrame<TPixel> paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame))
163+
using (IFrameQuantizer<TPixel> palleteFrameQuantizer = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()))
164+
using (QuantizedFrame<TPixel> paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame))
162165
{
163166
this.WriteImageData(paletteQuantized, stream);
164167
}
@@ -181,14 +184,17 @@ private void EncodeLocal<TPixel>(Image<TPixel> image, QuantizedFrame<TPixel> qua
181184
if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength
182185
&& frameMetadata.ColorTableLength > 0)
183186
{
184-
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(
185-
image.GetConfiguration(),
186-
frameMetadata.ColorTableLength).QuantizeFrame(frame);
187+
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration(), frameMetadata.ColorTableLength))
188+
{
189+
quantized = frameQuantizer.QuantizeFrame(frame);
190+
}
187191
}
188192
else
189193
{
190-
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())
191-
.QuantizeFrame(frame);
194+
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
195+
{
196+
quantized = frameQuantizer.QuantizeFrame(frame);
197+
}
192198
}
193199
}
194200

src/ImageSharp/Formats/Png/PngEncoderCore.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,11 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
243243
}
244244

245245
// Create quantized frame returning the palette and set the bit depth.
246-
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())
247-
.QuantizeFrame(image.Frames.RootFrame);
246+
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
247+
{
248+
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
249+
}
250+
248251
byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
249252
bits = Math.Max(bits, quantizedBits);
250253

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ public virtual QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
9898
return quantizedFrame;
9999
}
100100

101+
/// <inheritdoc/>
102+
public virtual void Dispose()
103+
{
104+
}
105+
101106
/// <summary>
102107
/// Execute the first pass through the pixels in the image to create the palette.
103108
/// </summary>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

4+
using System;
45
using SixLabors.ImageSharp.PixelFormats;
56
using SixLabors.ImageSharp.Processing.Processors.Dithering;
67

@@ -10,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
1011
/// Provides methods to allow the execution of the quantization process on an image frame.
1112
/// </summary>
1213
/// <typeparam name="TPixel">The pixel format.</typeparam>
13-
public interface IFrameQuantizer<TPixel>
14+
public interface IFrameQuantizer<TPixel> : IDisposable
1415
where TPixel : struct, IPixel<TPixel>
1516
{
1617
/// <summary>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public QuantizeProcessor(IQuantizer quantizer)
3333
/// <inheritdoc />
3434
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
3535
{
36-
IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>(configuration);
36+
using (IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>(configuration))
3737
using (QuantizedFrame<TPixel> quantized = executor.QuantizeFrame(source))
3838
{
3939
int paletteCount = quantized.Palette.Length - 1;

0 commit comments

Comments
 (0)