From bd7a2bca48809f8a37b3d74145de66feb99bb5ed Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 21 Jul 2024 17:42:01 +0200 Subject: [PATCH] Added special case for small amounts of data for all copying helpers --- HPPH/PixelHelper.Average.cs | 43 +++++++--- HPPH/PixelHelper.MinMax.cs | 43 +++++++--- HPPH/PixelHelper.Quantize.cs | 150 ++++++++++++++++++++++++++--------- HPPH/PixelHelper.Sum.cs | 43 +++++++--- 4 files changed, 210 insertions(+), 69 deletions(-) diff --git a/HPPH/PixelHelper.Average.cs b/HPPH/PixelHelper.Average.cs index b3744a2..df3ff5d 100644 --- a/HPPH/PixelHelper.Average.cs +++ b/HPPH/PixelHelper.Average.cs @@ -13,16 +13,27 @@ public static partial class PixelHelper ArgumentNullException.ThrowIfNull(image); int dataLength = image.SizeInBytes; - byte[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..dataLength]; - try + + if (dataLength <= 1024) { + Span buffer = stackalloc byte[dataLength]; + image.CopyTo(buffer); return image.ColorFormat.Average(buffer); } - finally + else { - ArrayPool.Shared.Return(array); + byte[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..dataLength]; + try + { + image.CopyTo(buffer); + return image.ColorFormat.Average(buffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } } @@ -34,16 +45,28 @@ public static partial class PixelHelper where T : struct, IColor { int dataLength = image.Width * image.Height; - T[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..(dataLength)]; - try + int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel; + + if (sizeInBytes <= 1024) { + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + image.CopyTo(buffer); return Average(buffer); } - finally + else { - ArrayPool.Shared.Return(array); + T[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..dataLength]; + try + { + image.CopyTo(buffer); + return Average(buffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } } diff --git a/HPPH/PixelHelper.MinMax.cs b/HPPH/PixelHelper.MinMax.cs index dbaed9f..008817f 100644 --- a/HPPH/PixelHelper.MinMax.cs +++ b/HPPH/PixelHelper.MinMax.cs @@ -14,16 +14,27 @@ public static unsafe partial class PixelHelper ArgumentNullException.ThrowIfNull(image); int dataLength = image.SizeInBytes; - byte[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..dataLength]; - try + + if (dataLength <= 1024) { + Span buffer = stackalloc byte[dataLength]; + image.CopyTo(buffer); return image.ColorFormat.MinMax(buffer); } - finally + else { - ArrayPool.Shared.Return(array); + byte[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..dataLength]; + try + { + image.CopyTo(buffer); + return image.ColorFormat.MinMax(buffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } } @@ -35,16 +46,28 @@ public static unsafe partial class PixelHelper where T : struct, IColor { int dataLength = image.Width * image.Height; - T[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..(dataLength)]; - try + int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel; + + if (sizeInBytes <= 1024) { + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + image.CopyTo(buffer); return MinMax(buffer); } - finally + else { - ArrayPool.Shared.Return(array); + T[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..(dataLength)]; + try + { + image.CopyTo(buffer); + return MinMax(buffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } } public static IMinMax MinMax(this Span colors) diff --git a/HPPH/PixelHelper.Quantize.cs b/HPPH/PixelHelper.Quantize.cs index b26feef..21f7354 100644 --- a/HPPH/PixelHelper.Quantize.cs +++ b/HPPH/PixelHelper.Quantize.cs @@ -1,5 +1,7 @@ using System.Buffers; using System.Numerics; +using System.Runtime.InteropServices; +using static System.Net.Mime.MediaTypeNames; namespace HPPH; @@ -12,16 +14,27 @@ public static partial class PixelHelper ArgumentNullException.ThrowIfNull(image); int dataLength = image.SizeInBytes; - byte[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..dataLength]; - try + + if (dataLength <= 1024) { + Span buffer = stackalloc byte[dataLength]; + image.CopyTo(buffer); return image.ColorFormat.CreateColorPalette(buffer, paletteSize); } - finally + else { - ArrayPool.Shared.Return(array); + byte[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..dataLength]; + try + { + image.CopyTo(buffer); + return image.ColorFormat.CreateColorPalette(buffer, paletteSize); + } + finally + { + ArrayPool.Shared.Return(array); + } } } @@ -33,33 +46,57 @@ public static partial class PixelHelper where T : unmanaged, IColor { int dataLength = image.Width * image.Height; - T[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..(dataLength)]; - try + int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel; + + if (sizeInBytes <= 1024) { + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + image.CopyTo(buffer); return CreateColorPalette(buffer, paletteSize); } - finally + else { - ArrayPool.Shared.Return(array); + T[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..(dataLength)]; + try + { + image.CopyTo(buffer); + return CreateColorPalette(buffer, paletteSize); + } + finally + { + ArrayPool.Shared.Return(array); + } } } public static T[] CreateColorPalette(this ReadOnlySpan colors, int paletteSize) where T : unmanaged, IColor { - T[] buffer = ArrayPool.Shared.Rent(colors.Length); - try - { - Span colorBuffer = buffer.AsSpan()[..colors.Length]; - colors.CopyTo(colorBuffer); + int sizeInBytes = colors.Length * T.ColorFormat.BytesPerPixel; - return CreateColorPalette(colorBuffer, paletteSize); - } - finally + if (sizeInBytes <= 1024) { - ArrayPool.Shared.Return(buffer); + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + + colors.CopyTo(buffer); + return CreateColorPalette(buffer, paletteSize); + } + else + { + T[] buffer = ArrayPool.Shared.Rent(colors.Length); + try + { + Span colorBuffer = buffer.AsSpan()[..colors.Length]; + colors.CopyTo(colorBuffer); + + return CreateColorPalette(colorBuffer, paletteSize); + } + finally + { + ArrayPool.Shared.Return(buffer); + } } } @@ -69,7 +106,7 @@ public static partial class PixelHelper throw new NotImplementedException("This requires some more research and will be implemented later"); //TODO DarthAffe 21.07.2024: Run some tests how the result to performance ratio is with the options described at http://blog.pkh.me/p/39-improving-color-quantization-heuristics.html - + //if (paletteSize < 0) throw new ArgumentException("PaletteSize can't be < 0", nameof(paletteSize)); //if (paletteSize == 0) return []; @@ -102,16 +139,27 @@ public static partial class PixelHelper ArgumentNullException.ThrowIfNull(image); int dataLength = image.SizeInBytes; - byte[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..dataLength]; - try + + if (dataLength <= 1024) { + Span buffer = stackalloc byte[dataLength]; + image.CopyTo(buffer); return image.ColorFormat.CreateSimpleColorPalette(buffer, paletteSize); } - finally + else { - ArrayPool.Shared.Return(array); + byte[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..dataLength]; + try + { + image.CopyTo(buffer); + return image.ColorFormat.CreateSimpleColorPalette(buffer, paletteSize); + } + finally + { + ArrayPool.Shared.Return(array); + } } } @@ -123,33 +171,57 @@ public static partial class PixelHelper where T : unmanaged, IColor { int dataLength = image.Width * image.Height; - T[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..(dataLength)]; - try + int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel; + + if (sizeInBytes <= 1024) { + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + image.CopyTo(buffer); return CreateSimpleColorPalette(buffer, paletteSize); } - finally + else { - ArrayPool.Shared.Return(array); + T[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..(dataLength)]; + try + { + image.CopyTo(buffer); + return CreateSimpleColorPalette(buffer, paletteSize); + } + finally + { + ArrayPool.Shared.Return(array); + } } } public static T[] CreateSimpleColorPalette(this ReadOnlySpan colors, int paletteSize) where T : unmanaged, IColor { - T[] buffer = ArrayPool.Shared.Rent(colors.Length); - try - { - Span colorBuffer = buffer.AsSpan()[..colors.Length]; - colors.CopyTo(colorBuffer); + int sizeInBytes = colors.Length * T.ColorFormat.BytesPerPixel; - return CreateSimpleColorPalette(colorBuffer, paletteSize); - } - finally + if (sizeInBytes <= 1024) { - ArrayPool.Shared.Return(buffer); + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + + colors.CopyTo(buffer); + return CreateSimpleColorPalette(buffer, paletteSize); + } + else + { + T[] buffer = ArrayPool.Shared.Rent(colors.Length); + try + { + Span colorBuffer = buffer.AsSpan()[..colors.Length]; + colors.CopyTo(colorBuffer); + + return CreateSimpleColorPalette(colorBuffer, paletteSize); + } + finally + { + ArrayPool.Shared.Return(buffer); + } } } diff --git a/HPPH/PixelHelper.Sum.cs b/HPPH/PixelHelper.Sum.cs index 34b0fa0..01b6df0 100644 --- a/HPPH/PixelHelper.Sum.cs +++ b/HPPH/PixelHelper.Sum.cs @@ -15,16 +15,27 @@ public static unsafe partial class PixelHelper ArgumentNullException.ThrowIfNull(image); int dataLength = image.SizeInBytes; - byte[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..dataLength]; - try + + if (dataLength <= 1024) { + Span buffer = stackalloc byte[dataLength]; + image.CopyTo(buffer); return image.ColorFormat.Sum(buffer); } - finally + else { - ArrayPool.Shared.Return(array); + byte[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..dataLength]; + try + { + image.CopyTo(buffer); + return image.ColorFormat.Sum(buffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } } @@ -36,16 +47,28 @@ public static unsafe partial class PixelHelper where T : struct, IColor { int dataLength = image.Width * image.Height; - T[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..(dataLength)]; - try + int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel; + + if (sizeInBytes <= 1024) { + Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); + image.CopyTo(buffer); return Sum(buffer); } - finally + else { - ArrayPool.Shared.Return(array); + T[] array = ArrayPool.Shared.Rent(dataLength); + Span buffer = array.AsSpan()[..(dataLength)]; + try + { + image.CopyTo(buffer); + return Sum(buffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } }