Last active
February 19, 2020 00:58
-
-
Save antonfirsov/cbad26bffc39fdd9803b7978a2e87abb to your computer and use it in GitHub Desktop.
Dithering and Quantization API proposal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface IFrameQuantizer<TPixel> | |
{ | |
QuantizerOptions Options { get; } | |
// Make FirstPass explicit on the interface. | |
// For single-step PaletteQuantizer this is NOP | |
void BuildPalette(ImageFrame<TPixel> image, Rectangle bounds); | |
ReadOnlyMemory<TPixel> Palette { get; } | |
// Note that we are always passing {palette: this.Palette.Span} | |
// Because of performance reasons | |
byte GetQuantizedColor(TPixel color, ReadOnlySpan<TPixel> palette, out TPixel match); | |
// FUTURE bulk variant | |
void GetQuantizedColors( | |
ReadOnlySpan<TPixel> colors, | |
ReadOnlySpan<TPixel> palette, | |
Span<byte> indices, S | |
pan<TPixel> matches); | |
} | |
// No need for a FrameQuantizer<TPixel> base class, since the shared logic is now moved | |
// to the QuantizerExtensions utility class. | |
// The quantizer should be a struct | |
public struct WuFrameQuantizer<TPixel> : IFrameQuantizer<TPixel> | |
{ | |
// ... | |
} | |
public interface IDither | |
{ | |
// Passing TQuantizer as a generic value-type argument enables devirtualization | |
void ApplyQuantizer<TPixel, TFrameQuantizer>( | |
TFrameQuantizer q, | |
ImageFrame<TPixel> frame, | |
Rectangle bounds, | |
Memory<byte> output, | |
ReadOnlyMemory<TPixel> palette) | |
where TFrameQuantizer : struct, IFrameQuantizer<TPixel>; | |
// To be used with PaletteDither processor. | |
// ??? how should TPaletteDitherThingie look like ??? | |
void ApplyPaletteDitherProcessor<TPixel, TPaletteDitherThingie>( | |
ImageFrame<TPixel> frame, | |
TPaletteDitherThingie paletteDither); | |
} | |
public static class QuantizerExtensions | |
{ | |
public static QuantizeFrame<TFrameQuantizer, TPixel>( | |
this TFrameQuantizer q, | |
ImageFrame<TPixel> image, | |
Rectangle bounds) | |
where TFrameQuantizer : IFrameQuantizer<TPixel> | |
{ | |
// contains current QuantizeFrame logic, invoking SecondPass | |
} | |
private static void SecondPass<TFrameQuantizer, TPixel>( | |
TFrameQuantizer q, | |
ImageFrame<TPixel> frame, | |
Rectangle bounds, | |
Memory<byte> output, | |
ReadOnlyMemory<TPixel> palette) | |
where TFrameQuantizer : IFrameuantizer<TPixel> | |
{ | |
q.Options.Dither.ApplyQuantizer(q, frame, bounds, output, palette); | |
} | |
} | |
internal class ErrorDiffusion : IDither | |
{ | |
public void ApplyQuantizer<TPixel, TQuantizer>( | |
TFrameQuantizer q, | |
ImageFrame<TPixel> frame, | |
Rectangle bounds, | |
Memory<byte> output, | |
ReadOnlyMemory<TPixel> palette) | |
where TQuantizer : struct, IFrameQuantizer<TPixel> | |
{ | |
// contains the current logic from FrameQuantizer L164-L180 | |
// + ErrorDither.Dither | |
// Calls to q.GetQuantizedColor(...) are expected to be devirtualized & inlined | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment