mirror of https://github.com/SixLabors/ImageSharp
95 changed files with 1340 additions and 565 deletions
@ -0,0 +1,103 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Dithering; |
|||
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced |
|||
{ |
|||
/// <summary>
|
|||
/// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being
|
|||
/// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics,
|
|||
/// these are caused because not every possible generic instantiation can be determined up front at compile time.
|
|||
/// The Aot Compiler is designed to overcome the limitations of this compiler.
|
|||
/// </summary>
|
|||
public static class AotCompilerTools |
|||
{ |
|||
/// <summary>
|
|||
/// Seeds the compiler using the given pixel format.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
public static void Seed<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
// This is we actually call all the individual methods you need to seed.
|
|||
AotCompileOctreeQuantizer<TPixel>(); |
|||
AotCompileWuQuantizer<TPixel>(); |
|||
AotCompileDithering<TPixel>(); |
|||
|
|||
// TODO: Do the discovery work to figure out what works and what doesn't.
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Seeds the compiler using the given pixel formats.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The first pixel format.</typeparam>
|
|||
/// <typeparam name="TPixel2">The second pixel format.</typeparam>
|
|||
public static void Seed<TPixel, TPixel2>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
where TPixel2 : struct, IPixel<TPixel2> |
|||
{ |
|||
Seed<TPixel>(); |
|||
Seed<TPixel2>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Seeds the compiler using the given pixel formats.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The first pixel format.</typeparam>
|
|||
/// <typeparam name="TPixel2">The second pixel format.</typeparam>
|
|||
/// <typeparam name="TPixel3">The third pixel format.</typeparam>
|
|||
public static void Seed<TPixel, TPixel2, TPixel3>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
where TPixel2 : struct, IPixel<TPixel2> |
|||
where TPixel3 : struct, IPixel<TPixel3> |
|||
{ |
|||
Seed<TPixel, TPixel2>(); |
|||
Seed<TPixel3>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method doesn't actually do anything but serves an important purpose...
|
|||
/// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion:
|
|||
/// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode."
|
|||
/// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT
|
|||
/// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on
|
|||
/// iOS so it bombs out.
|
|||
/// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the
|
|||
/// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!!
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
private static void AotCompileOctreeQuantizer<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var test = new OctreeFrameQuantizer<TPixel>(new OctreeQuantizer(false)); |
|||
test.AotGetPalette(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method pre-seeds the WuQuantizer in the AoT compiler for iOS.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
private static void AotCompileWuQuantizer<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var test = new WuFrameQuantizer<TPixel>(new WuQuantizer(false)); |
|||
test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1)); |
|||
test.AotGetPalette(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
private static void AotCompileDithering<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var test = new FloydSteinbergDiffuser(); |
|||
TPixel pixel = default; |
|||
test.Dither<TPixel>(new ImageFrame<TPixel>(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,110 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Dithering; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Quantization |
|||
{ |
|||
/// <summary>
|
|||
/// A generic palette quantizer.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
public class PaletteQuantizer<TPixel> : IQuantizer |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="palette">The color palette to use.</param>
|
|||
public PaletteQuantizer(TPixel[] palette) |
|||
: this(palette, true) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="palette">The color palette to use.</param>
|
|||
/// <param name="dither">Whether to apply dithering to the output image</param>
|
|||
public PaletteQuantizer(TPixel[] palette, bool dither) |
|||
: this(palette, GetDiffuser(dither)) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="palette">The color palette to use.</param>
|
|||
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
|
|||
public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); |
|||
this.Palette = palette; |
|||
this.Diffuser = diffuser; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IErrorDiffuser Diffuser { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the palette.
|
|||
/// </summary>
|
|||
public TPixel[] Palette { get; } |
|||
|
|||
/// <summary>
|
|||
/// Creates the generic frame quantizer.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
|
|||
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/>.</returns>
|
|||
public IFrameQuantizer<TPixel> CreateFrameQuantizer(Configuration configuration) |
|||
=> ((IQuantizer)this).CreateFrameQuantizer<TPixel>(configuration); |
|||
|
|||
/// <summary>
|
|||
/// Creates the generic frame quantizer.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
|
|||
/// <param name="maxColors">The maximum number of colors to hold in the color palette.</param>
|
|||
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/>.</returns>
|
|||
public IFrameQuantizer<TPixel> CreateFrameQuantizer(Configuration configuration, int maxColors) |
|||
=> ((IQuantizer)this).CreateFrameQuantizer<TPixel>(configuration, maxColors); |
|||
|
|||
/// <inheritdoc/>
|
|||
IFrameQuantizer<TPixel1> IQuantizer.CreateFrameQuantizer<TPixel1>(Configuration configuration) |
|||
{ |
|||
if (!typeof(TPixel).Equals(typeof(TPixel1))) |
|||
{ |
|||
throw new InvalidOperationException("Generic method type must be the same as class type."); |
|||
} |
|||
|
|||
TPixel[] paletteRef = this.Palette; |
|||
return new PaletteFrameQuantizer<TPixel1>(this, Unsafe.As<TPixel[], TPixel1[]>(ref paletteRef)); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
IFrameQuantizer<TPixel1> IQuantizer.CreateFrameQuantizer<TPixel1>(Configuration configuration, int maxColors) |
|||
{ |
|||
if (!typeof(TPixel).Equals(typeof(TPixel1))) |
|||
{ |
|||
throw new InvalidOperationException("Generic method type must be the same as class type."); |
|||
} |
|||
|
|||
TPixel[] paletteRef = this.Palette; |
|||
TPixel1[] castPalette = Unsafe.As<TPixel[], TPixel1[]>(ref paletteRef); |
|||
|
|||
maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); |
|||
int max = Math.Min(maxColors, castPalette.Length); |
|||
|
|||
if (max != castPalette.Length) |
|||
{ |
|||
return new PaletteFrameQuantizer<TPixel1>(this, castPalette.AsSpan(0, max).ToArray()); |
|||
} |
|||
|
|||
return new PaletteFrameQuantizer<TPixel1>(this, castPalette); |
|||
} |
|||
|
|||
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Quantization |
|||
{ |
|||
/// <summary>
|
|||
/// Contains color quantization specific constants.
|
|||
/// </summary>
|
|||
internal static class QuantizerConstants |
|||
{ |
|||
/// <summary>
|
|||
/// The minimum number of colors to use when quantizing an image.
|
|||
/// </summary>
|
|||
public const int MinColors = 1; |
|||
|
|||
/// <summary>
|
|||
/// The maximum number of colors to use when quantizing an image.
|
|||
/// </summary>
|
|||
public const int MaxColors = 256; |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Dithering; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Quantization |
|||
{ |
|||
/// <summary>
|
|||
/// A palette quantizer consisting of web safe colors as defined in the CSS Color Module Level 4.
|
|||
/// </summary>
|
|||
public class WebSafePaletteQuantizer : PaletteQuantizer |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WebSafePaletteQuantizer" /> class.
|
|||
/// </summary>
|
|||
public WebSafePaletteQuantizer() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WebSafePaletteQuantizer" /> class.
|
|||
/// </summary>
|
|||
/// <param name="dither">Whether to apply dithering to the output image</param>
|
|||
public WebSafePaletteQuantizer(bool dither) |
|||
: base(dither) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WebSafePaletteQuantizer" /> class.
|
|||
/// </summary>
|
|||
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
|
|||
public WebSafePaletteQuantizer(IErrorDiffuser diffuser) |
|||
: base(diffuser) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration) |
|||
=> this.CreateFrameQuantizer<TPixel>(configuration, NamedColors<TPixel>.WebSafePalette.Length); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors) |
|||
=> this.CreateFrameQuantizer(configuration, NamedColors<TPixel>.WebSafePalette, maxColors); |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Dithering; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Quantization |
|||
{ |
|||
/// <summary>
|
|||
/// A palette quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821.
|
|||
/// The hex codes were collected and defined by Nicholas Rougeux <see href="https://www.c82.net/werner"/>
|
|||
/// </summary>
|
|||
public class WernerPaletteQuantizer : PaletteQuantizer |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WernerPaletteQuantizer" /> class.
|
|||
/// </summary>
|
|||
public WernerPaletteQuantizer() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WernerPaletteQuantizer" /> class.
|
|||
/// </summary>
|
|||
/// <param name="dither">Whether to apply dithering to the output image</param>
|
|||
public WernerPaletteQuantizer(bool dither) |
|||
: base(dither) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WernerPaletteQuantizer" /> class.
|
|||
/// </summary>
|
|||
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
|
|||
public WernerPaletteQuantizer(IErrorDiffuser diffuser) |
|||
: base(diffuser) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration) |
|||
=> this.CreateFrameQuantizer<TPixel>(configuration, NamedColors<TPixel>.WernerPalette.Length); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors) |
|||
=> this.CreateFrameQuantizer(configuration, NamedColors<TPixel>.WernerPalette, maxColors); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Advanced |
|||
{ |
|||
public class AotCompilerTests |
|||
{ |
|||
[Fact] |
|||
public void AotCompiler_NoExceptions() |
|||
{ |
|||
AotCompilerTools.Seed<Rgba32>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization |
|||
{ |
|||
public class OctreeQuantizerTests |
|||
{ |
|||
[Fact] |
|||
public void OctreeQuantizerConstructor() |
|||
{ |
|||
var quantizer = new OctreeQuantizer(128); |
|||
|
|||
Assert.Equal(128, quantizer.MaxColors); |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); |
|||
|
|||
quantizer = new OctreeQuantizer(false); |
|||
Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); |
|||
Assert.Null(quantizer.Diffuser); |
|||
|
|||
quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); |
|||
Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); |
|||
Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); |
|||
|
|||
quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson, 128); |
|||
Assert.Equal(128, quantizer.MaxColors); |
|||
Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); |
|||
} |
|||
|
|||
[Fact] |
|||
public void OctreeQuantizerCanCreateFrameQuantizer() |
|||
{ |
|||
var quantizer = new OctreeQuantizer(); |
|||
IFrameQuantizer<Rgba32> frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(Configuration.Default); |
|||
|
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.True(frameQuantizer.Dither); |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); |
|||
|
|||
quantizer = new OctreeQuantizer(false); |
|||
frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(Configuration.Default); |
|||
|
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.False(frameQuantizer.Dither); |
|||
Assert.Null(frameQuantizer.Diffuser); |
|||
|
|||
quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); |
|||
frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(Configuration.Default); |
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.True(frameQuantizer.Dither); |
|||
Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization |
|||
{ |
|||
public class PaletteQuantizerTests |
|||
{ |
|||
private static readonly Rgba32[] Rgb = new Rgba32[] { Rgba32.Red, Rgba32.Green, Rgba32.Blue }; |
|||
|
|||
[Fact] |
|||
public void PaletteQuantizerConstructor() |
|||
{ |
|||
var quantizer = new PaletteQuantizer<Rgba32>(Rgb); |
|||
|
|||
Assert.Equal(Rgb, quantizer.Palette); |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); |
|||
|
|||
quantizer = new PaletteQuantizer<Rgba32>(Rgb, false); |
|||
Assert.Equal(Rgb, quantizer.Palette); |
|||
Assert.Null(quantizer.Diffuser); |
|||
|
|||
quantizer = new PaletteQuantizer<Rgba32>(Rgb, KnownDiffusers.Atkinson); |
|||
Assert.Equal(Rgb, quantizer.Palette); |
|||
Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); |
|||
} |
|||
|
|||
[Fact] |
|||
public void PaletteQuantizerCanCreateFrameQuantizer() |
|||
{ |
|||
var quantizer = new PaletteQuantizer<Rgba32>(Rgb); |
|||
IFrameQuantizer<Rgba32> frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); |
|||
|
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.True(frameQuantizer.Dither); |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); |
|||
|
|||
quantizer = new PaletteQuantizer<Rgba32>(Rgb, false); |
|||
frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); |
|||
|
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.False(frameQuantizer.Dither); |
|||
Assert.Null(frameQuantizer.Diffuser); |
|||
|
|||
quantizer = new PaletteQuantizer<Rgba32>(Rgb, KnownDiffusers.Atkinson); |
|||
frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); |
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.True(frameQuantizer.Dither); |
|||
Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); |
|||
} |
|||
|
|||
[Fact] |
|||
public void PaletteQuantizerThrowsOnInvalidGenericMethodCall() |
|||
{ |
|||
var quantizer = new PaletteQuantizer<Rgba32>(Rgb); |
|||
|
|||
Assert.Throws<InvalidOperationException>(() => ((IQuantizer)quantizer).CreateFrameQuantizer<Rgb24>(Configuration.Default)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void KnownQuantizersWebSafeTests() |
|||
{ |
|||
IQuantizer quantizer = KnownQuantizers.WebSafe; |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); |
|||
} |
|||
|
|||
[Fact] |
|||
public void KnownQuantizersWernerTests() |
|||
{ |
|||
IQuantizer quantizer = KnownQuantizers.Werner; |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization |
|||
{ |
|||
public class WuQuantizerTests |
|||
{ |
|||
[Fact] |
|||
public void WuQuantizerConstructor() |
|||
{ |
|||
var quantizer = new WuQuantizer(128); |
|||
|
|||
Assert.Equal(128, quantizer.MaxColors); |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); |
|||
|
|||
quantizer = new WuQuantizer(false); |
|||
Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); |
|||
Assert.Null(quantizer.Diffuser); |
|||
|
|||
quantizer = new WuQuantizer(KnownDiffusers.Atkinson); |
|||
Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); |
|||
Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); |
|||
|
|||
quantizer = new WuQuantizer(KnownDiffusers.Atkinson, 128); |
|||
Assert.Equal(128, quantizer.MaxColors); |
|||
Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); |
|||
} |
|||
|
|||
[Fact] |
|||
public void WuQuantizerCanCreateFrameQuantizer() |
|||
{ |
|||
var quantizer = new WuQuantizer(); |
|||
IFrameQuantizer<Rgba32> frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(Configuration.Default); |
|||
|
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.True(frameQuantizer.Dither); |
|||
Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); |
|||
|
|||
quantizer = new WuQuantizer(false); |
|||
frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(Configuration.Default); |
|||
|
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.False(frameQuantizer.Dither); |
|||
Assert.Null(frameQuantizer.Diffuser); |
|||
|
|||
quantizer = new WuQuantizer(KnownDiffusers.Atkinson); |
|||
frameQuantizer = quantizer.CreateFrameQuantizer<Rgba32>(Configuration.Default); |
|||
Assert.NotNull(frameQuantizer); |
|||
Assert.True(frameQuantizer.Dither); |
|||
Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); |
|||
} |
|||
} |
|||
} |
|||
@ -1 +1 @@ |
|||
Subproject commit f41ae0327a3ab21ab2388c32160bda67debcc082 |
|||
Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 |
|||
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 267 B |
Loading…
Reference in new issue