mirror of https://github.com/SixLabors/ImageSharp
18 changed files with 545 additions and 221 deletions
@ -0,0 +1,92 @@ |
|||||
|
// 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> |
||||
|
{ |
||||
|
private readonly TPixel[] palette; |
||||
|
|
||||
|
/// <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; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IFrameQuantizer<TPixel1> CreateFrameQuantizer<TPixel1>() |
||||
|
where TPixel1 : struct, IPixel<TPixel1> |
||||
|
{ |
||||
|
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/>
|
||||
|
public IFrameQuantizer<TPixel1> CreateFrameQuantizer<TPixel1>(int maxColors) |
||||
|
where TPixel1 : struct, IPixel<TPixel1> |
||||
|
{ |
||||
|
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>() |
||||
|
=> this.CreateFrameQuantizer<TPixel>(NamedColors<TPixel>.WebSafePalette.Length); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(int maxColors) |
||||
|
=> this.CreateFrameQuantizer(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>() |
||||
|
=> this.CreateFrameQuantizer<TPixel>(NamedColors<TPixel>.WernerPalette.Length); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(int maxColors) |
||||
|
=> this.CreateFrameQuantizer(NamedColors<TPixel>.WernerPalette, maxColors); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue