diff --git a/HPPH.Benchmark/AverageBenchmarks.cs b/HPPH.Benchmark/AverageBenchmarks.cs index 9708606..5920a86 100644 --- a/HPPH.Benchmark/AverageBenchmarks.cs +++ b/HPPH.Benchmark/AverageBenchmarks.cs @@ -13,6 +13,8 @@ public class AverageBenchmarks private readonly List _colors3bpp; private readonly List _colors4bpp; + private readonly List> _images3bpp; + private readonly List> _images4bpp; #endregion @@ -22,6 +24,9 @@ public class AverageBenchmarks { _colors3bpp = BenchmarkHelper.GetSampleData(); _colors4bpp = BenchmarkHelper.GetSampleData(); + + _images3bpp = BenchmarkHelper.GetSampleDataImages(); + _images4bpp = BenchmarkHelper.GetSampleDataImages(); } #endregion @@ -48,6 +53,26 @@ public class AverageBenchmarks return averages; } + [Benchmark] + public ColorRGB[] PixelHelper_3BPP_Image() + { + ColorRGB[] averages = new ColorRGB[_images3bpp.Count]; + for (int i = 0; i < _images3bpp.Count; i++) + averages[i] = _images3bpp[i].Average(); + + return averages; + } + + [Benchmark] + public ColorRGBA[] PixelHelper_4BPP_Image() + { + ColorRGBA[] averages = new ColorRGBA[_images4bpp.Count]; + for (int i = 0; i < _images4bpp.Count; i++) + averages[i] = _images4bpp[i].Average(); + + return averages; + } + [Benchmark] public ColorRGB[] Reference_3BPP() { diff --git a/HPPH.Generators/ColorFormatSourceGenerator.cs b/HPPH.Generators/ColorFormatSourceGenerator.cs index 4f631f1..f445c79 100644 --- a/HPPH.Generators/ColorFormatSourceGenerator.cs +++ b/HPPH.Generators/ColorFormatSourceGenerator.cs @@ -19,7 +19,6 @@ public class ColorSourceGenerator : IIncrementalGenerator private static readonly IGeneratorFeature[] FEATURES = [ new Colors(), - new Average(), new MinMax(), new Sum(), new Quantize() diff --git a/HPPH.Generators/Features/Average.cs b/HPPH.Generators/Features/Average.cs deleted file mode 100644 index 7cbd884..0000000 --- a/HPPH.Generators/Features/Average.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; - -namespace HPPH.Generators; - -internal class Average : IGeneratorFeature -{ - public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat) - { - yield return ($"ColorFormat{colorFormat.Format}.Average", GenerateColorFormatAverage(colorFormat)); - } - - public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray colorFormats) - { - yield return ("IColorFormat.Average", GenerateColorFormatInterfaceAverage()); - } - - private static string GenerateColorFormatAverage(ColorFormatData colorFormat) - { - return $$""" - #nullable enable - - using System.Runtime.InteropServices; - - namespace HPPH; - - public sealed partial class ColorFormat{{colorFormat.Format}} - { - #region Methods - - unsafe IColor IColorFormat.Average(ReadOnlySpan data) => PixelHelper.Average(MemoryMarshal.Cast(data)); - - #endregion - } - """; - } - - private static string GenerateColorFormatInterfaceAverage() - { - return """ - #nullable enable - - namespace HPPH; - - public partial interface IColorFormat - { - internal IColor Average(ReadOnlySpan data); - } - """; - } -} \ No newline at end of file diff --git a/HPPH.Generators/Features/Colors.cs b/HPPH.Generators/Features/Colors.cs index 9e44537..32b3e54 100644 --- a/HPPH.Generators/Features/Colors.cs +++ b/HPPH.Generators/Features/Colors.cs @@ -218,6 +218,12 @@ internal class Colors : IGeneratorFeature private ColorFormat{{colorFormat.Format}}() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => Color{{colorFormat.Format}}.Create(r, g, b, a); + + #endregion } """; } @@ -243,6 +249,8 @@ internal class Colors : IGeneratorFeature sb.AppendLine(); sb.AppendLine(""" + IColor CreateColor(byte r, byte g, byte b, byte a); + #endregion } """); diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatABGR.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatABGR.g.cs index 3644f8c..247851c 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatABGR.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatABGR.g.cs @@ -21,4 +21,10 @@ public sealed partial class ColorFormatABGR : IColorFormat private ColorFormatABGR() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorABGR.Create(r, g, b, a); + + #endregion } \ No newline at end of file diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatARGB.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatARGB.g.cs index 19d9357..0448cb6 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatARGB.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatARGB.g.cs @@ -21,4 +21,10 @@ public sealed partial class ColorFormatARGB : IColorFormat private ColorFormatARGB() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorARGB.Create(r, g, b, a); + + #endregion } \ No newline at end of file diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGR.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGR.g.cs index e895511..92053f2 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGR.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGR.g.cs @@ -21,4 +21,10 @@ public sealed partial class ColorFormatBGR : IColorFormat private ColorFormatBGR() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorBGR.Create(r, g, b, a); + + #endregion } \ No newline at end of file diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGRA.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGRA.g.cs index a3c290e..6cd472b 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGRA.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatBGRA.g.cs @@ -21,4 +21,10 @@ public sealed partial class ColorFormatBGRA : IColorFormat private ColorFormatBGRA() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorBGRA.Create(r, g, b, a); + + #endregion } \ No newline at end of file diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGB.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGB.g.cs index e6c1852..b694e70 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGB.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGB.g.cs @@ -21,4 +21,10 @@ public sealed partial class ColorFormatRGB : IColorFormat private ColorFormatRGB() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorRGB.Create(r, g, b, a); + + #endregion } \ No newline at end of file diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGBA.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGBA.g.cs index a3a44b0..b8c8e60 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGBA.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorFormatRGBA.g.cs @@ -21,4 +21,10 @@ public sealed partial class ColorFormatRGBA : IColorFormat private ColorFormatRGBA() {} #endregion + + #region Methods + + public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorRGBA.Create(r, g, b, a); + + #endregion } \ No newline at end of file diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/IColorFormat.Instances.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/IColorFormat.Instances.g.cs index 4533389..1fd4a3b 100644 --- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/IColorFormat.Instances.g.cs +++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/IColorFormat.Instances.g.cs @@ -13,5 +13,7 @@ public partial interface IColorFormat public static ColorFormatRGBA RGBA => ColorFormatRGBA.Instance; public static ColorFormatBGRA BGRA => ColorFormatBGRA.Instance; + IColor CreateColor(byte r, byte g, byte b, byte a); + #endregion } diff --git a/HPPH/PixelHelper.Average.cs b/HPPH/PixelHelper.Average.cs index 5ac2c62..85b70aa 100644 --- a/HPPH/PixelHelper.Average.cs +++ b/HPPH/PixelHelper.Average.cs @@ -1,5 +1,4 @@ -using System.Buffers; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace HPPH; @@ -12,29 +11,14 @@ public static partial class PixelHelper { ArgumentNullException.ThrowIfNull(image); - int dataLength = image.SizeInBytes; + float count = image.Width * image.Height; - if (dataLength <= 1024) - { - Span buffer = stackalloc byte[dataLength]; + ISum sum = Sum(image); - image.CopyTo(buffer); - return image.ColorFormat.Average(buffer); - } - else - { - 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); - } - } + return image.ColorFormat.CreateColor((byte)MathF.Round(sum.R / count), + (byte)MathF.Round(sum.G / count), + (byte)MathF.Round(sum.B / count), + (byte)MathF.Round(sum.A / count)); } public static T Average(this IImage image) @@ -48,30 +32,13 @@ public static partial class PixelHelper public static T Average(this RefImage image) where T : struct, IColor { - int dataLength = image.Width * image.Height; - int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel; + float count = image.Width * image.Height; - if (sizeInBytes <= 1024) - { - Span buffer = MemoryMarshal.Cast(stackalloc byte[sizeInBytes]); - - image.CopyTo(buffer); - return Average(buffer); - } - else - { - T[] array = ArrayPool.Shared.Rent(dataLength); - Span buffer = array.AsSpan()[..dataLength]; - try - { - image.CopyTo(buffer); - return Average(buffer); - } - finally - { - ArrayPool.Shared.Return(array); - } - } + ISum sum = Sum(image); + return (T)T.Create((byte)MathF.Round(sum.R / count), + (byte)MathF.Round(sum.G / count), + (byte)MathF.Round(sum.B / count), + (byte)MathF.Round(sum.A / count)); } public static T Average(this Span colors)