Added special case for small amounts of data for all copying helpers

This commit is contained in:
Darth Affe 2024-07-21 17:42:01 +02:00
parent cfdd95f079
commit bd7a2bca48
4 changed files with 210 additions and 69 deletions

View File

@ -13,16 +13,27 @@ public static partial class PixelHelper
ArgumentNullException.ThrowIfNull(image); ArgumentNullException.ThrowIfNull(image);
int dataLength = image.SizeInBytes; int dataLength = image.SizeInBytes;
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength]; if (dataLength <= 1024)
try
{ {
Span<byte> buffer = stackalloc byte[dataLength];
image.CopyTo(buffer); image.CopyTo(buffer);
return image.ColorFormat.Average(buffer); return image.ColorFormat.Average(buffer);
} }
finally else
{ {
ArrayPool<byte>.Shared.Return(array); byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength];
try
{
image.CopyTo(buffer);
return image.ColorFormat.Average(buffer);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
}
} }
} }
@ -34,16 +45,28 @@ public static partial class PixelHelper
where T : struct, IColor where T : struct, IColor
{ {
int dataLength = image.Width * image.Height; int dataLength = image.Width * image.Height;
T[] array = ArrayPool<T>.Shared.Rent(dataLength); int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
Span<T> buffer = array.AsSpan()[..(dataLength)];
try if (sizeInBytes <= 1024)
{ {
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
image.CopyTo(buffer); image.CopyTo(buffer);
return Average(buffer); return Average(buffer);
} }
finally else
{ {
ArrayPool<T>.Shared.Return(array); T[] array = ArrayPool<T>.Shared.Rent(dataLength);
Span<T> buffer = array.AsSpan()[..dataLength];
try
{
image.CopyTo(buffer);
return Average(buffer);
}
finally
{
ArrayPool<T>.Shared.Return(array);
}
} }
} }

View File

@ -14,16 +14,27 @@ public static unsafe partial class PixelHelper
ArgumentNullException.ThrowIfNull(image); ArgumentNullException.ThrowIfNull(image);
int dataLength = image.SizeInBytes; int dataLength = image.SizeInBytes;
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength]; if (dataLength <= 1024)
try
{ {
Span<byte> buffer = stackalloc byte[dataLength];
image.CopyTo(buffer); image.CopyTo(buffer);
return image.ColorFormat.MinMax(buffer); return image.ColorFormat.MinMax(buffer);
} }
finally else
{ {
ArrayPool<byte>.Shared.Return(array); byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength];
try
{
image.CopyTo(buffer);
return image.ColorFormat.MinMax(buffer);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
}
} }
} }
@ -35,16 +46,28 @@ public static unsafe partial class PixelHelper
where T : struct, IColor where T : struct, IColor
{ {
int dataLength = image.Width * image.Height; int dataLength = image.Width * image.Height;
T[] array = ArrayPool<T>.Shared.Rent(dataLength); int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
Span<T> buffer = array.AsSpan()[..(dataLength)];
try if (sizeInBytes <= 1024)
{ {
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
image.CopyTo(buffer); image.CopyTo(buffer);
return MinMax(buffer); return MinMax(buffer);
} }
finally else
{ {
ArrayPool<T>.Shared.Return(array); T[] array = ArrayPool<T>.Shared.Rent(dataLength);
Span<T> buffer = array.AsSpan()[..(dataLength)];
try
{
image.CopyTo(buffer);
return MinMax(buffer);
}
finally
{
ArrayPool<T>.Shared.Return(array);
}
} }
} }
public static IMinMax MinMax<T>(this Span<T> colors) public static IMinMax MinMax<T>(this Span<T> colors)

View File

@ -1,5 +1,7 @@
using System.Buffers; using System.Buffers;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices;
using static System.Net.Mime.MediaTypeNames;
namespace HPPH; namespace HPPH;
@ -12,16 +14,27 @@ public static partial class PixelHelper
ArgumentNullException.ThrowIfNull(image); ArgumentNullException.ThrowIfNull(image);
int dataLength = image.SizeInBytes; int dataLength = image.SizeInBytes;
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength]; if (dataLength <= 1024)
try
{ {
Span<byte> buffer = stackalloc byte[dataLength];
image.CopyTo(buffer); image.CopyTo(buffer);
return image.ColorFormat.CreateColorPalette(buffer, paletteSize); return image.ColorFormat.CreateColorPalette(buffer, paletteSize);
} }
finally else
{ {
ArrayPool<byte>.Shared.Return(array); byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength];
try
{
image.CopyTo(buffer);
return image.ColorFormat.CreateColorPalette(buffer, paletteSize);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
}
} }
} }
@ -33,33 +46,57 @@ public static partial class PixelHelper
where T : unmanaged, IColor where T : unmanaged, IColor
{ {
int dataLength = image.Width * image.Height; int dataLength = image.Width * image.Height;
T[] array = ArrayPool<T>.Shared.Rent(dataLength); int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
Span<T> buffer = array.AsSpan()[..(dataLength)];
try if (sizeInBytes <= 1024)
{ {
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
image.CopyTo(buffer); image.CopyTo(buffer);
return CreateColorPalette(buffer, paletteSize); return CreateColorPalette(buffer, paletteSize);
} }
finally else
{ {
ArrayPool<T>.Shared.Return(array); T[] array = ArrayPool<T>.Shared.Rent(dataLength);
Span<T> buffer = array.AsSpan()[..(dataLength)];
try
{
image.CopyTo(buffer);
return CreateColorPalette(buffer, paletteSize);
}
finally
{
ArrayPool<T>.Shared.Return(array);
}
} }
} }
public static T[] CreateColorPalette<T>(this ReadOnlySpan<T> colors, int paletteSize) public static T[] CreateColorPalette<T>(this ReadOnlySpan<T> colors, int paletteSize)
where T : unmanaged, IColor where T : unmanaged, IColor
{ {
T[] buffer = ArrayPool<T>.Shared.Rent(colors.Length); int sizeInBytes = colors.Length * T.ColorFormat.BytesPerPixel;
try
{
Span<T> colorBuffer = buffer.AsSpan()[..colors.Length];
colors.CopyTo(colorBuffer);
return CreateColorPalette(colorBuffer, paletteSize); if (sizeInBytes <= 1024)
}
finally
{ {
ArrayPool<T>.Shared.Return(buffer); Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
colors.CopyTo(buffer);
return CreateColorPalette(buffer, paletteSize);
}
else
{
T[] buffer = ArrayPool<T>.Shared.Rent(colors.Length);
try
{
Span<T> colorBuffer = buffer.AsSpan()[..colors.Length];
colors.CopyTo(colorBuffer);
return CreateColorPalette(colorBuffer, paletteSize);
}
finally
{
ArrayPool<T>.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"); 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 //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) throw new ArgumentException("PaletteSize can't be < 0", nameof(paletteSize));
//if (paletteSize == 0) return []; //if (paletteSize == 0) return [];
@ -102,16 +139,27 @@ public static partial class PixelHelper
ArgumentNullException.ThrowIfNull(image); ArgumentNullException.ThrowIfNull(image);
int dataLength = image.SizeInBytes; int dataLength = image.SizeInBytes;
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength]; if (dataLength <= 1024)
try
{ {
Span<byte> buffer = stackalloc byte[dataLength];
image.CopyTo(buffer); image.CopyTo(buffer);
return image.ColorFormat.CreateSimpleColorPalette(buffer, paletteSize); return image.ColorFormat.CreateSimpleColorPalette(buffer, paletteSize);
} }
finally else
{ {
ArrayPool<byte>.Shared.Return(array); byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength];
try
{
image.CopyTo(buffer);
return image.ColorFormat.CreateSimpleColorPalette(buffer, paletteSize);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
}
} }
} }
@ -123,33 +171,57 @@ public static partial class PixelHelper
where T : unmanaged, IColor where T : unmanaged, IColor
{ {
int dataLength = image.Width * image.Height; int dataLength = image.Width * image.Height;
T[] array = ArrayPool<T>.Shared.Rent(dataLength); int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
Span<T> buffer = array.AsSpan()[..(dataLength)];
try if (sizeInBytes <= 1024)
{ {
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
image.CopyTo(buffer); image.CopyTo(buffer);
return CreateSimpleColorPalette(buffer, paletteSize); return CreateSimpleColorPalette(buffer, paletteSize);
} }
finally else
{ {
ArrayPool<T>.Shared.Return(array); T[] array = ArrayPool<T>.Shared.Rent(dataLength);
Span<T> buffer = array.AsSpan()[..(dataLength)];
try
{
image.CopyTo(buffer);
return CreateSimpleColorPalette(buffer, paletteSize);
}
finally
{
ArrayPool<T>.Shared.Return(array);
}
} }
} }
public static T[] CreateSimpleColorPalette<T>(this ReadOnlySpan<T> colors, int paletteSize) public static T[] CreateSimpleColorPalette<T>(this ReadOnlySpan<T> colors, int paletteSize)
where T : unmanaged, IColor where T : unmanaged, IColor
{ {
T[] buffer = ArrayPool<T>.Shared.Rent(colors.Length); int sizeInBytes = colors.Length * T.ColorFormat.BytesPerPixel;
try
{
Span<T> colorBuffer = buffer.AsSpan()[..colors.Length];
colors.CopyTo(colorBuffer);
return CreateSimpleColorPalette(colorBuffer, paletteSize); if (sizeInBytes <= 1024)
}
finally
{ {
ArrayPool<T>.Shared.Return(buffer); Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
colors.CopyTo(buffer);
return CreateSimpleColorPalette(buffer, paletteSize);
}
else
{
T[] buffer = ArrayPool<T>.Shared.Rent(colors.Length);
try
{
Span<T> colorBuffer = buffer.AsSpan()[..colors.Length];
colors.CopyTo(colorBuffer);
return CreateSimpleColorPalette(colorBuffer, paletteSize);
}
finally
{
ArrayPool<T>.Shared.Return(buffer);
}
} }
} }

View File

@ -15,16 +15,27 @@ public static unsafe partial class PixelHelper
ArgumentNullException.ThrowIfNull(image); ArgumentNullException.ThrowIfNull(image);
int dataLength = image.SizeInBytes; int dataLength = image.SizeInBytes;
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength]; if (dataLength <= 1024)
try
{ {
Span<byte> buffer = stackalloc byte[dataLength];
image.CopyTo(buffer); image.CopyTo(buffer);
return image.ColorFormat.Sum(buffer); return image.ColorFormat.Sum(buffer);
} }
finally else
{ {
ArrayPool<byte>.Shared.Return(array); byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
Span<byte> buffer = array.AsSpan()[..dataLength];
try
{
image.CopyTo(buffer);
return image.ColorFormat.Sum(buffer);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
}
} }
} }
@ -36,16 +47,28 @@ public static unsafe partial class PixelHelper
where T : struct, IColor where T : struct, IColor
{ {
int dataLength = image.Width * image.Height; int dataLength = image.Width * image.Height;
T[] array = ArrayPool<T>.Shared.Rent(dataLength); int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
Span<T> buffer = array.AsSpan()[..(dataLength)];
try if (sizeInBytes <= 1024)
{ {
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
image.CopyTo(buffer); image.CopyTo(buffer);
return Sum(buffer); return Sum(buffer);
} }
finally else
{ {
ArrayPool<T>.Shared.Return(array); T[] array = ArrayPool<T>.Shared.Rent(dataLength);
Span<T> buffer = array.AsSpan()[..(dataLength)];
try
{
image.CopyTo(buffer);
return Sum(buffer);
}
finally
{
ArrayPool<T>.Shared.Return(array);
}
} }
} }