Browse Source

Merge pull request #452 from SixLabors/js/fix-semi-opaque-dithering

Fix and optimize error diffusion
pull/455/head
James Jackson-South 8 years ago
committed by GitHub
parent
commit
e4293f95b3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs
  2. 2
      src/ImageSharp/Formats/Png/PngEncoder.cs
  3. 2
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  4. 2
      src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs
  5. 4
      src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
  6. 12
      tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs

8
src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs

@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Dithering.Base
this.startingOffset = 0; this.startingOffset = 0;
for (int i = 0; i < this.matrixWidth; i++) for (int i = 0; i < this.matrixWidth; i++)
{ {
// Good to disable here as we are not comparing matematical output. // Good to disable here as we are not comparing mathematical output.
// ReSharper disable once CompareOfFloatsByEqualityOperator // ReSharper disable once CompareOfFloatsByEqualityOperator
if (matrix[0, i] != 0) if (matrix[0, i] != 0)
{ {
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Dithering.Base
// Calculate the error // Calculate the error
Vector4 error = source.ToVector4() - transformed.ToVector4(); Vector4 error = source.ToVector4() - transformed.ToVector4();
// Loop through and distribute the error amongst neighbouring pixels. // Loop through and distribute the error amongst neighboring pixels.
for (int row = 0; row < this.matrixHeight; row++) for (int row = 0; row < this.matrixHeight; row++)
{ {
int matrixY = y + row; int matrixY = y + row;
@ -115,10 +115,8 @@ namespace SixLabors.ImageSharp.Dithering.Base
ref TPixel pixel = ref rowSpan[matrixX]; ref TPixel pixel = ref rowSpan[matrixX];
var offsetColor = pixel.ToVector4(); var offsetColor = pixel.ToVector4();
var coefficientVector = new Vector4(coefficient);
Vector4 result = ((error * coefficientVector) / this.divisorVector) + offsetColor; Vector4 result = ((error * coefficient) / this.divisorVector) + offsetColor;
result.W = offsetColor.W;
pixel.PackFromVector4(result); pixel.PackFromVector4(result);
} }
} }

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

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public bool IgnoreMetadata { get; set; } public bool IgnoreMetadata { get; set; }
/// <summary> /// <summary>
/// Gets or sets the size of the color palette to use. Set to zero to leav png encoding to use pixel data. /// Gets or sets the size of the color palette to use. Set to zero to leave png encoding to use pixel data.
/// </summary> /// </summary>
public int PaletteSize { get; set; } = 0; public int PaletteSize { get; set; } = 0;

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

@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class. /// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary> /// </summary>
/// <param name="options">The options for influancing the encoder</param> /// <param name="options">The options for influencing the encoder</param>
public PngEncoderCore(IPngEncoderOptions options) public PngEncoderCore(IPngEncoderOptions options)
{ {
this.ignoreMetadata = options.IgnoreMetadata; this.ignoreMetadata = options.IgnoreMetadata;

2
src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Quantizers.Base
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Dither { get; set; } = false; public bool Dither { get; set; } = true;
/// <inheritdoc /> /// <inheritdoc />
public IErrorDiffuser DitherType { get; set; } = new FloydSteinbergDiffuser(); public IErrorDiffuser DitherType { get; set; } = new FloydSteinbergDiffuser();

4
src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs

@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.Quantizers
} }
/// <summary> /// <summary>
/// Gets the index index of the given color in the palette. /// Gets the index of the given color in the palette.
/// </summary> /// </summary>
/// <param name="r">The red value.</param> /// <param name="r">The red value.</param>
/// <param name="g">The green value.</param> /// <param name="g">The green value.</param>
@ -827,7 +827,7 @@ namespace SixLabors.ImageSharp.Quantizers
{ {
if (this.Dither) if (this.Dither)
{ {
// The colors have changed so we need to use Euclidean distance caclulation to find the closest value. // The colors have changed so we need to use Euclidean distance calculation to find the closest value.
// This palette can never be null here. // This palette can never be null here.
return this.GetClosestPixel(pixel, this.palette, this.colorMap); return this.GetClosestPixel(pixel, this.palette, this.colorMap);
} }

12
tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs

@ -7,6 +7,18 @@
public class QuantizedImageTests public class QuantizedImageTests
{ {
[Fact]
public void QuantizersDitherByDefault()
{
var palette = new PaletteQuantizer<Rgba32>();
var octree = new OctreeQuantizer<Rgba32>();
var wu = new WuQuantizer<Rgba32>();
Assert.True(palette.Dither);
Assert.True(octree.Dither);
Assert.True(wu.Dither);
}
[Theory] [Theory]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)]

Loading…
Cancel
Save