From eab8a9623695e3565a1a746515fa522f918a9fdb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 15 Nov 2021 12:14:33 +0100 Subject: [PATCH] quantizer mess --- src/ImageSharp/Advanced/AotCompilerTools.cs | 8 ++--- .../Dithering/ErroDither.KnownTypes.cs | 2 +- .../Processors/Dithering/ErrorDither.cs | 26 +++++++------- .../Processors/Dithering/IDither.cs | 8 ++--- .../Dithering/OrderedDither.KnownTypes.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 31 +++++++++------- .../PaletteDitherProcessor{TPixel}.cs | 4 +-- .../Quantization/EuclideanPixelMap{TPixel}.cs | 36 +++++++++++++------ .../Quantization/OctreeQuantizer{TPixel}.cs | 16 ++++++--- .../Quantization/PaletteQuantizer{TPixel}.cs | 12 ++++--- .../Quantization/QuantizerUtilities.cs | 16 ++++----- .../Quantization/WuQuantizer{TPixel}.cs | 13 ++++--- 12 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index b90a6ce3cd..eae4bb4898 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -508,16 +508,16 @@ namespace SixLabors.ImageSharp.Advanced [Preserve] private static void AotCompileDither() where TPixel : unmanaged, IPixel - where TDither : struct, IDither + where TDither : class, IDither { var octree = default(OctreeQuantizer); - default(TDither).ApplyQuantizationDither, TPixel>(ref octree, default, default, default); + default(TDither).ApplyQuantizationDither, TPixel>(octree, default, default, default); var palette = default(PaletteQuantizer); - default(TDither).ApplyQuantizationDither, TPixel>(ref palette, default, default, default); + default(TDither).ApplyQuantizationDither, TPixel>(palette, default, default, default); var wu = default(WuQuantizer); - default(TDither).ApplyQuantizationDither, TPixel>(ref wu, default, default, default); + default(TDither).ApplyQuantizationDither, TPixel>(wu, default, default, default); default(TDither).ApplyPaletteDither.DitherProcessor, TPixel>(default, default, default); } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs b/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs index 4c01fb4023..90df6c7108 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// An error diffusion dithering implementation. /// - public readonly partial struct ErrorDither + public partial class ErrorDither { /// /// Applies error diffusion based dithering using the Atkinson image dithering algorithm. diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 27bb660e9e..37171a2ed3 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// An error diffusion dithering implementation. /// /// - public readonly partial struct ErrorDither : IDither, IEquatable, IEquatable + public partial class ErrorDither : IDither, IEquatable, IEquatable { private readonly int offset; private readonly DenseMatrix matrix; @@ -91,17 +91,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// [MethodImpl(InliningOptions.ShortMethod)] public void ApplyQuantizationDither( - ref TFrameQuantizer quantizer, + TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IQuantizer + where TFrameQuantizer : class, IQuantizer where TPixel : unmanaged, IPixel { - if (this == default) - { - ThrowDefaultInstance(); - } + // if (this == default) + // { + // ThrowDefaultInstance(); + // } int offsetY = bounds.Top; int offsetX = bounds.Left; @@ -131,16 +131,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// [MethodImpl(InliningOptions.ShortMethod)] public void ApplyPaletteDither( - in TPaletteDitherImageProcessor processor, + TPaletteDitherImageProcessor processor, ImageFrame source, Rectangle bounds) - where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor + where TPaletteDitherImageProcessor : class, IPaletteDitherImageProcessor where TPixel : unmanaged, IPixel { - if (this == default) - { - ThrowDefaultInstance(); - } + // if (this == default) + // { + // ThrowDefaultInstance(); + // } Buffer2D sourceBuffer = source.PixelBuffer; float scale = processor.DitherScale; diff --git a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs index 1b046c7bc7..24846db307 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs @@ -22,11 +22,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The destination quantized frame. /// The region of interest bounds. void ApplyQuantizationDither( - ref TFrameQuantizer quantizer, + TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IQuantizer + where TFrameQuantizer : class, IQuantizer where TPixel : unmanaged, IPixel; /// @@ -39,10 +39,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The source image. /// The region of interest bounds. void ApplyPaletteDither( - in TPaletteDitherImageProcessor processor, + TPaletteDitherImageProcessor processor, ImageFrame source, Rectangle bounds) - where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor + where TPaletteDitherImageProcessor : class, IPaletteDitherImageProcessor where TPixel : unmanaged, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs index 1934604522..a89b239f30 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// An ordered dithering matrix with equal sides of arbitrary length /// - public readonly partial struct OrderedDither + public partial class OrderedDither { /// /// Applies order dithering using the 2x2 Bayer dithering matrix. diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index da0a852b8c..6338bc5b3c 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// An ordered dithering matrix with equal sides of arbitrary length /// - public readonly partial struct OrderedDither : IDither, IEquatable, IEquatable + public partial class OrderedDither : IDither, IEquatable, IEquatable { private readonly DenseMatrix thresholdMatrix; private readonly int modulusX; @@ -105,17 +105,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// [MethodImpl(InliningOptions.ShortMethod)] public void ApplyQuantizationDither( - ref TFrameQuantizer quantizer, + TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IQuantizer + where TFrameQuantizer : class, IQuantizer where TPixel : unmanaged, IPixel { - if (this == default) - { - ThrowDefaultInstance(); - } + // if (this == default) + // { + // ThrowDefaultInstance(); + // } int spread = CalculatePaletteSpread(destination.Palette.Length); float scale = quantizer.Options.DitherScale; @@ -134,19 +134,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering } } + // public void ApplyQuantizationDither(TFrameQuantizer quantizer, ImageFrame source, + // IndexedImageFrame destination, Rectangle bounds) + // where TFrameQuantizer : class, IQuantizer where TPixel : unmanaged, IPixel => + // throw new NotImplementedException(); + /// [MethodImpl(InliningOptions.ShortMethod)] public void ApplyPaletteDither( - in TPaletteDitherImageProcessor processor, + TPaletteDitherImageProcessor processor, ImageFrame source, Rectangle bounds) - where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor + where TPaletteDitherImageProcessor : class, IPaletteDitherImageProcessor where TPixel : unmanaged, IPixel { - if (this == default) - { - ThrowDefaultInstance(); - } + // if (this == default) + // { + // ThrowDefaultInstance(); + // } int spread = CalculatePaletteSpread(processor.Palette.Length); float scale = processor.DitherScale; diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 07af8a5af0..3b02a965d2 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering protected override void OnFrameApply(ImageFrame source) { var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - this.dither.ApplyPaletteDither(in this.ditherProcessor, source, interest); + this.dither.ApplyPaletteDither(this.ditherProcessor, source, interest); } /// @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// . /// /// Internal for AOT - internal readonly struct DitherProcessor : IPaletteDitherImageProcessor, IDisposable + internal class DitherProcessor : IPaletteDitherImageProcessor, IDisposable { private readonly EuclideanPixelMap pixelMap; diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index b82ce71bbd..071bd4643a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : unmanaged, IPixel { private Rgba32[] rgbaPalette; - private readonly ColorDistanceCache cache; + private ColorDistanceCache cache; private readonly Configuration configuration; /// @@ -136,7 +136,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return (deltaR * deltaR) + (deltaG * deltaG) + (deltaB * deltaB) + (deltaA * deltaA); } - public void Dispose() => this.cache.Dispose(); + public void Dispose() + { + this.cache.Dispose(); + GC.SuppressFinalize(this); + } + + ~EuclideanPixelMap() => throw new Exception("very bad"); /// /// A cache for storing color distance matching results. @@ -149,7 +155,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Entry count is currently limited to 1185921 entries (2371842 bytes ~2.26MB). /// /// - private unsafe struct ColorDistanceCache : IDisposable + private class ColorDistanceCache : IDisposable { private const int IndexBits = 5; private const int IndexAlphaBits = 5; @@ -158,16 +164,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private const int RgbShift = 8 - IndexBits; private const int AlphaShift = 8 - IndexAlphaBits; private const int Entries = IndexCount * IndexCount * IndexCount * IndexAlphaCount; - private MemoryHandle tableHandle; + // private MemoryHandle tableHandle; private readonly IMemoryOwner table; - private readonly short* tablePointer; + // private readonly short* tablePointer; + private Memory tableMemory; public ColorDistanceCache(MemoryAllocator allocator) { this.table = allocator.Allocate(Entries); this.table.GetSpan().Fill(-1); - this.tableHandle = this.table.Memory.Pin(); - this.tablePointer = (short*)this.tableHandle.Pointer; + this.tableMemory = this.table.Memory; + // this.tableHandle = this.table.Memory.Pin(); + // this.tablePointer = (short*)this.tableHandle.Pointer; } [MethodImpl(InliningOptions.ShortMethod)] @@ -178,7 +186,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization int b = rgba.B >> RgbShift; int a = rgba.A >> AlphaShift; int idx = GetPaletteIndex(r, g, b, a); - this.tablePointer[idx] = index; + // this.tablePointer[idx] = index; + this.table.Memory.Span[idx] = index; } [MethodImpl(InliningOptions.ShortMethod)] @@ -189,7 +198,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization int b = rgba.B >> RgbShift; int a = rgba.A >> AlphaShift; int idx = GetPaletteIndex(r, g, b, a); - match = this.tablePointer[idx]; + // match = this.tablePointer[idx]; + match = this.tableMemory.Span[idx]; return match > -1; } @@ -214,9 +224,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { if (this.table != null) { - this.tableHandle.Dispose(); + // this.tableHandle.Dispose(); this.table.Dispose(); } + GC.SuppressFinalize(this); + } + + ~ColorDistanceCache() + { + throw new Exception("very bad"); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index e28de54c25..99a41a3c87 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -16,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - public struct OctreeQuantizer : IQuantizer + public class OctreeQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly int maxColors; @@ -52,6 +53,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.isDisposed = false; } + ~OctreeQuantizer() + { + throw new Exception("Very bad"); + } + /// public Configuration Configuration { get; } @@ -126,12 +132,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + public IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => QuantizerUtilities.QuantizeFrame(this, source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly byte GetQuantizedColor(TPixel color, out TPixel match) + public byte GetQuantizedColor(TPixel color, out TPixel match) { // Octree only maps the RGB component of a color // so cannot tell the difference between a fully transparent @@ -158,6 +164,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.pixelMap?.Dispose(); this.pixelMap = null; } + + GC.SuppressFinalize(this); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index 284f4fa701..1a338d5700 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -13,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal struct PaletteQuantizer : IQuantizer + internal class PaletteQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private EuclideanPixelMap pixelMap; @@ -35,6 +36,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.pixelMap = new EuclideanPixelMap(configuration, palette); } + ~PaletteQuantizer() => throw new Exception("Very bad"); + /// public Configuration Configuration { get; } @@ -46,8 +49,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + public IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => QuantizerUtilities.QuantizeFrame(this, source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -57,7 +60,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly byte GetQuantizedColor(TPixel color, out TPixel match) + public byte GetQuantizedColor(TPixel color, out TPixel match) => (byte)this.pixelMap.GetClosestColor(color, out match); /// @@ -65,6 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { this.pixelMap?.Dispose(); this.pixelMap = null; + GC.SuppressFinalize(this); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index 5aa79d732e..c70f2079a8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -71,10 +71,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// A representing a quantized version of the source frame pixels. /// public static IndexedImageFrame QuantizeFrame( - ref TFrameQuantizer quantizer, + TFrameQuantizer quantizer, ImageFrame source, Rectangle bounds) - where TFrameQuantizer : struct, IQuantizer + where TFrameQuantizer : class, IQuantizer where TPixel : unmanaged, IPixel { Guard.NotNull(source, nameof(source)); @@ -88,13 +88,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (quantizer.Options.Dither is null) { - SecondPass(ref quantizer, source, destination, interest); + SecondPass(quantizer, source, destination, interest); } else { // We clone the image as we don't want to alter the original via error diffusion based dithering. using ImageFrame clone = source.Clone(); - SecondPass(ref quantizer, clone, destination, interest); + SecondPass(quantizer, clone, destination, interest); } return destination; @@ -114,11 +114,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] private static void SecondPass( - ref TFrameQuantizer quantizer, + TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IQuantizer + where TFrameQuantizer : class, IQuantizer where TPixel : unmanaged, IPixel { IDither dither = quantizer.Options.Dither; @@ -136,14 +136,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int x = bounds.Left; x < bounds.Right; x++) { - destinationRow[x - offsetX] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x], out TPixel _); + destinationRow[x - offsetX] = quantizer.GetQuantizedColor(sourceRow[x], out TPixel _); } } return; } - dither.ApplyQuantizationDither(ref quantizer, source, destination, bounds); + dither.ApplyQuantizationDither(quantizer, source, destination, bounds); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index cc53299528..e7b6b74e35 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -31,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal struct WuQuantizer : IQuantizer + internal class WuQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly MemoryAllocator memoryAllocator; @@ -100,6 +101,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.isDithering = this.isDithering = !(this.Options.Dither is null); } + ~WuQuantizer() => throw new Exception("very bad"); + /// public Configuration Configuration { get; } @@ -162,11 +165,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + public IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => QuantizerUtilities.QuantizeFrame(this, source, bounds); /// - public readonly byte GetQuantizedColor(TPixel color, out TPixel match) + public byte GetQuantizedColor(TPixel color, out TPixel match) { if (this.isDithering) { @@ -203,6 +206,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.pixelMap?.Dispose(); this.pixelMap = null; } + + GC.SuppressFinalize(this); } ///