diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index eae4bb4898..b90a6ce3cd 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 : class, IDither + where TDither : struct, IDither { var octree = default(OctreeQuantizer); - default(TDither).ApplyQuantizationDither, TPixel>(octree, default, default, default); + default(TDither).ApplyQuantizationDither, TPixel>(ref octree, default, default, default); var palette = default(PaletteQuantizer); - default(TDither).ApplyQuantizationDither, TPixel>(palette, default, default, default); + default(TDither).ApplyQuantizationDither, TPixel>(ref palette, default, default, default); var wu = default(WuQuantizer); - default(TDither).ApplyQuantizationDither, TPixel>(wu, default, default, default); + default(TDither).ApplyQuantizationDither, TPixel>(ref 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 90df6c7108..4c01fb4023 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 partial class ErrorDither + public readonly partial struct 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 37171a2ed3..27bb660e9e 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 partial class ErrorDither : IDither, IEquatable, IEquatable + public readonly partial struct 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( - TFrameQuantizer quantizer, + ref TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : class, IQuantizer + where TFrameQuantizer : struct, 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( - TPaletteDitherImageProcessor processor, + in TPaletteDitherImageProcessor processor, ImageFrame source, Rectangle bounds) - where TPaletteDitherImageProcessor : class, IPaletteDitherImageProcessor + where TPaletteDitherImageProcessor : struct, 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 24846db307..1b046c7bc7 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( - TFrameQuantizer quantizer, + ref TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : class, IQuantizer + where TFrameQuantizer : struct, 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( - TPaletteDitherImageProcessor processor, + in TPaletteDitherImageProcessor processor, ImageFrame source, Rectangle bounds) - where TPaletteDitherImageProcessor : class, IPaletteDitherImageProcessor + where TPaletteDitherImageProcessor : struct, 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 a89b239f30..1934604522 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 partial class OrderedDither + public readonly partial struct 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 6338bc5b3c..da0a852b8c 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 partial class OrderedDither : IDither, IEquatable, IEquatable + public readonly partial struct 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( - TFrameQuantizer quantizer, + ref TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : class, IQuantizer + where TFrameQuantizer : struct, 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,24 +134,19 @@ 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( - TPaletteDitherImageProcessor processor, + in TPaletteDitherImageProcessor processor, ImageFrame source, Rectangle bounds) - where TPaletteDitherImageProcessor : class, IPaletteDitherImageProcessor + where TPaletteDitherImageProcessor : struct, 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 3b02a965d2..07af8a5af0 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(this.ditherProcessor, source, interest); + this.dither.ApplyPaletteDither(in this.ditherProcessor, source, interest); } /// @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// . /// /// Internal for AOT - internal class DitherProcessor : IPaletteDitherImageProcessor, IDisposable + internal readonly struct 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 071bd4643a..b82ce71bbd 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 ColorDistanceCache cache; + private readonly ColorDistanceCache cache; private readonly Configuration configuration; /// @@ -136,13 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return (deltaR * deltaR) + (deltaG * deltaG) + (deltaB * deltaB) + (deltaA * deltaA); } - public void Dispose() - { - this.cache.Dispose(); - GC.SuppressFinalize(this); - } - - ~EuclideanPixelMap() => throw new Exception("very bad"); + public void Dispose() => this.cache.Dispose(); /// /// A cache for storing color distance matching results. @@ -155,7 +149,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Entry count is currently limited to 1185921 entries (2371842 bytes ~2.26MB). /// /// - private class ColorDistanceCache : IDisposable + private unsafe struct ColorDistanceCache : IDisposable { private const int IndexBits = 5; private const int IndexAlphaBits = 5; @@ -164,18 +158,16 @@ 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 Memory tableMemory; + private readonly short* tablePointer; public ColorDistanceCache(MemoryAllocator allocator) { this.table = allocator.Allocate(Entries); this.table.GetSpan().Fill(-1); - this.tableMemory = this.table.Memory; - // this.tableHandle = this.table.Memory.Pin(); - // this.tablePointer = (short*)this.tableHandle.Pointer; + this.tableHandle = this.table.Memory.Pin(); + this.tablePointer = (short*)this.tableHandle.Pointer; } [MethodImpl(InliningOptions.ShortMethod)] @@ -186,8 +178,7 @@ 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.table.Memory.Span[idx] = index; + this.tablePointer[idx] = index; } [MethodImpl(InliningOptions.ShortMethod)] @@ -198,8 +189,7 @@ 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.tableMemory.Span[idx]; + match = this.tablePointer[idx]; return match > -1; } @@ -224,15 +214,9 @@ 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 99a41a3c87..e28de54c25 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -5,7 +5,6 @@ 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; @@ -17,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - public class OctreeQuantizer : IQuantizer + public struct OctreeQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly int maxColors; @@ -53,11 +52,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.isDisposed = false; } - ~OctreeQuantizer() - { - throw new Exception("Very bad"); - } - /// public Configuration Configuration { get; } @@ -132,12 +126,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(this, source, bounds); + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public byte GetQuantizedColor(TPixel color, out TPixel match) + public readonly 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 @@ -164,8 +158,6 @@ 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 1a338d5700..284f4fa701 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -14,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal class PaletteQuantizer : IQuantizer + internal struct PaletteQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private EuclideanPixelMap pixelMap; @@ -36,8 +35,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.pixelMap = new EuclideanPixelMap(configuration, palette); } - ~PaletteQuantizer() => throw new Exception("Very bad"); - /// public Configuration Configuration { get; } @@ -49,8 +46,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(this, source, bounds); + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -60,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public byte GetQuantizedColor(TPixel color, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, out TPixel match) => (byte)this.pixelMap.GetClosestColor(color, out match); /// @@ -68,7 +65,6 @@ 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 c70f2079a8..5aa79d732e 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( - TFrameQuantizer quantizer, + ref TFrameQuantizer quantizer, ImageFrame source, Rectangle bounds) - where TFrameQuantizer : class, IQuantizer + where TFrameQuantizer : struct, 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(quantizer, source, destination, interest); + SecondPass(ref 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(quantizer, clone, destination, interest); + SecondPass(ref quantizer, clone, destination, interest); } return destination; @@ -114,11 +114,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] private static void SecondPass( - TFrameQuantizer quantizer, + ref TFrameQuantizer quantizer, ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : class, IQuantizer + where TFrameQuantizer : struct, 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] = quantizer.GetQuantizedColor(sourceRow[x], out TPixel _); + destinationRow[x - offsetX] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x], out TPixel _); } } return; } - dither.ApplyQuantizationDither(quantizer, source, destination, bounds); + dither.ApplyQuantizationDither(ref 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 e7b6b74e35..cc53299528 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -5,7 +5,6 @@ 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; @@ -32,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal class WuQuantizer : IQuantizer + internal struct WuQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly MemoryAllocator memoryAllocator; @@ -101,8 +100,6 @@ 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; } @@ -165,11 +162,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(this, source, bounds); + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// - public byte GetQuantizedColor(TPixel color, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, out TPixel match) { if (this.isDithering) { @@ -206,8 +203,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.pixelMap?.Dispose(); this.pixelMap = null; } - - GC.SuppressFinalize(this); } ///