diff --git a/HPPH.Generators/Features/Colors.cs b/HPPH.Generators/Features/Colors.cs
index a091c78..9a6da84 100644
--- a/HPPH.Generators/Features/Colors.cs
+++ b/HPPH.Generators/Features/Colors.cs
@@ -74,6 +74,9 @@ internal class Colors : IGeneratorFeature
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
@@ -137,6 +140,9 @@ internal class Colors : IGeneratorFeature
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH.Reference/PixelHelper.Quantize.cs b/HPPH.Reference/PixelHelper.Quantize.cs
index 8abeff2..c6e92ae 100644
--- a/HPPH.Reference/PixelHelper.Quantize.cs
+++ b/HPPH.Reference/PixelHelper.Quantize.cs
@@ -6,8 +6,9 @@ public static partial class ReferencePixelHelper
{
#region Methods
- public static IColor[] CreateColorPalette(IImage image, int paletteSize)
- => CreateColorPalette(image.ToArray(), paletteSize);
+ public static T[] CreateColorPalette(Image image, int paletteSize)
+ where T : unmanaged, IColor
+ => CreateColorPalette(image.ToArray(), paletteSize);
public static T[] CreateColorPalette(RefImage image, int paletteSize)
where T : unmanaged, IColor
@@ -15,17 +16,20 @@ public static partial class ReferencePixelHelper
public static T[] CreateColorPalette(Span colors, int paletteSize)
where T : unmanaged, IColor =>
- CreateColorPalette(colors.ToArray().Cast().ToArray(), paletteSize).Select(x => T.Create(x.R, x.G, x.B, x.A)).Cast().ToArray();
+ CreateColorPalette(colors.ToArray().Cast().ToArray(), paletteSize).Select(x => T.Create(x.R, x.G, x.B, x.A)).Cast().ToArray();
- private static IColor[] CreateColorPalette(IColor[] colors, int paletteSize)
+ private static IColor[] CreateColorPalette(IColor[] colors, int paletteSize)
+ where T : struct, IColor
{
+ if (paletteSize == 0) return [];
+
int splits = BitOperations.Log2((uint)paletteSize);
- List cubes = [new ColorCube(colors)];
+ HashSet cubes = [new ColorCube(colors)];
for (int i = 0; i < splits; i++)
{
- List currentCubes = [.. cubes];
+ HashSet currentCubes = [.. cubes];
foreach (ColorCube currentCube in currentCubes)
{
currentCube.Split(out ColorCube a, out ColorCube b);
@@ -35,7 +39,7 @@ public static partial class ReferencePixelHelper
}
}
- return cubes.Select(c => c.GetAverageColor()).ToArray();
+ return cubes.Select(c => c.GetAverageColor()).ToArray();
}
#endregion
@@ -53,6 +57,12 @@ internal class ColorCube
internal ColorCube(IList colors)
{
+ if (colors.Count == 0)
+ {
+ _colors = [];
+ return;
+ }
+
int redRange = colors.Max(c => c.R) - colors.Min(c => c.R);
int greenRange = colors.Max(c => c.G) - colors.Min(c => c.G);
int blueRange = colors.Max(c => c.B) - colors.Min(c => c.B);
@@ -77,17 +87,20 @@ internal class ColorCube
b = new ColorCube(_colors.GetRange(median, _colors.Count - median));
}
- internal IColor GetAverageColor()
+ internal IColor GetAverageColor()
+ where T : struct, IColor
{
+ if (_colors.Count == 0) return T.Create(0, 0, 0, 0);
+
int r = _colors.Sum(x => x.R);
int g = _colors.Sum(x => x.G);
int b = _colors.Sum(x => x.B);
int a = _colors.Sum(x => x.A);
- return new ColorRGBA((byte)(r / _colors.Count),
- (byte)(g / _colors.Count),
- (byte)(b / _colors.Count),
- (byte)(a / _colors.Count));
+ return T.Create((byte)(r / _colors.Count),
+ (byte)(g / _colors.Count),
+ (byte)(b / _colors.Count),
+ (byte)(a / _colors.Count));
}
#endregion
diff --git a/HPPH.Test/Colors/MinMaxStructTests.cs b/HPPH.Test/Colors/MinMaxStructTests.cs
index 81cdfe3..f3b0c41 100644
--- a/HPPH.Test/Colors/MinMaxStructTests.cs
+++ b/HPPH.Test/Colors/MinMaxStructTests.cs
@@ -1,6 +1,4 @@
-using System.Runtime.InteropServices;
-
-namespace HPPH.Test.Colors;
+namespace HPPH.Test.Colors;
[TestClass]
public class MinMaxStructTests
diff --git a/HPPH.Test/Image/ImageTest.cs b/HPPH.Test/Image/ImageTest.cs
index 59d7ac9..b2ee5c1 100644
--- a/HPPH.Test/Image/ImageTest.cs
+++ b/HPPH.Test/Image/ImageTest.cs
@@ -15,7 +15,7 @@ public class ImageTest
#region Methods
[TestMethod]
- public void TestImageCreation()
+ public void ImageCreation()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
@@ -28,7 +28,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageInnerFull()
+ public void ImageInnerFull()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
image = image[0, 0, image.Width, image.Height];
@@ -39,7 +39,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageEnumerator()
+ public void ImageEnumerator()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
@@ -56,7 +56,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageInnerPartial()
+ public void ImageInnerPartial()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
image = image[163, 280, 720, 13];
@@ -70,7 +70,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageInnerInnerPartial()
+ public void ImageInnerInnerPartial()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
image = image[163, 280, 720, 13];
@@ -85,7 +85,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageRowIndexer()
+ public void ImageRowIndexer()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
@@ -101,7 +101,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageRowEnumerator()
+ public void ImageRowEnumerator()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
@@ -116,7 +116,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageColumnIndexer()
+ public void ImageColumnIndexer()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
@@ -132,7 +132,7 @@ public class ImageTest
}
[TestMethod]
- public void TestImageColumnEnumerator()
+ public void ImageColumnEnumerator()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
@@ -147,7 +147,7 @@ public class ImageTest
}
[TestMethod]
- public void TestAsRefImage()
+ public void AsRefImage()
{
IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
image = image[163, 280, 720, 13];
@@ -417,6 +417,16 @@ public class ImageTest
y++;
}
+
+ y = 0;
+ foreach (IImageRow row in (IEnumerable)image.Rows)
+ {
+ int x = 0;
+ foreach (IColor color in (IEnumerable)row)
+ Assert.AreEqual(TestDataHelper.GetColorFromLocation(x++, y), color);
+
+ y++;
+ }
}
[TestMethod]
@@ -509,5 +519,53 @@ public class ImageTest
}
}
+ [TestMethod]
+ public void InterfaceRowsCopyTo()
+ {
+ IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
+
+ int y = 0;
+ foreach (IImageRow row in image.Rows)
+ {
+ IColor[] colors = new IColor[TEST_WIDTH];
+ byte[] bytes = new byte[TEST_WIDTH * 4];
+ row.CopyTo(colors);
+ row.CopyTo(bytes);
+
+ int x = 0;
+ foreach (IColor color in colors)
+ Assert.AreEqual(TestDataHelper.GetColorFromLocation(x++, y), color);
+
+ for (x = 0; x < TEST_WIDTH; x++)
+ {
+ IColor reference = TestDataHelper.GetColorFromLocation(x, y);
+
+ Assert.AreEqual(reference.A, bytes[(x * 4) + 0]);
+ Assert.AreEqual(reference.R, bytes[(x * 4) + 1]);
+ Assert.AreEqual(reference.G, bytes[(x * 4) + 2]);
+ Assert.AreEqual(reference.B, bytes[(x * 4) + 3]);
+ }
+
+ y++;
+ }
+ }
+
+ [TestMethod]
+ public void InterfaceRowsToArray()
+ {
+ IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT);
+
+ int y = 0;
+ foreach (IImageRow row in image.Rows)
+ {
+ IColor[] data = row.ToArray();
+
+ for (int x = 0; x < TEST_WIDTH; x++)
+ Assert.AreEqual(TestDataHelper.GetColorFromLocation(x, y), data[x]);
+
+ y++;
+ }
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/HPPH.Test/Image/RefImageTest.cs b/HPPH.Test/Image/RefImageTest.cs
index cf043b3..6134657 100644
--- a/HPPH.Test/Image/RefImageTest.cs
+++ b/HPPH.Test/Image/RefImageTest.cs
@@ -15,7 +15,7 @@ public class RefImageTest
#region Methods
[TestMethod]
- public void TestImageCreation()
+ public void ImageCreation()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
@@ -28,7 +28,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageInnerFull()
+ public void ImageInnerFull()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
image = image[0, 0, image.Width, image.Height];
@@ -39,7 +39,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageEnumerator()
+ public void ImageEnumerator()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
@@ -49,7 +49,7 @@ public class RefImageTest
int x = counter % image.Width;
int y = counter / image.Width;
- if(y == 1) Debugger.Break();
+ if (y == 1) Debugger.Break();
Assert.AreEqual(TestDataHelper.GetColorFromLocation(x, y), color);
@@ -58,7 +58,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageInnerPartial()
+ public void ImageInnerPartial()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
image = image[163, 280, 720, 13];
@@ -72,7 +72,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageInnerInnerPartial()
+ public void ImageInnerInnerPartial()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
image = image[163, 280, 720, 13];
@@ -87,7 +87,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageRowIndexer()
+ public void ImageRowIndexer()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
@@ -103,7 +103,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageRowEnumerator()
+ public void ImageRowEnumerator()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
@@ -118,7 +118,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageColumnIndexer()
+ public void ImageColumnIndexer()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
@@ -134,7 +134,7 @@ public class RefImageTest
}
[TestMethod]
- public void TestImageColumnEnumerator()
+ public void ImageColumnEnumerator()
{
RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
@@ -148,5 +148,57 @@ public class RefImageTest
}
}
+ [TestMethod]
+ public void ToArray()
+ {
+ RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
+ ColorARGB[] testData = image.ToArray();
+
+ for (int y = 0; y < TEST_HEIGHT; y++)
+ for (int x = 0; x < TEST_WIDTH; x++)
+ Assert.AreEqual(TestDataHelper.GetColorFromLocation(x, y), testData[(y * TEST_WIDTH) + x]);
+ }
+
+ [TestMethod]
+ public void CopyTo()
+ {
+ RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
+ ColorARGB[] testData = new ColorARGB[TEST_WIDTH * TEST_HEIGHT];
+ image.CopyTo(testData);
+
+ for (int y = 0; y < TEST_HEIGHT; y++)
+ for (int x = 0; x < TEST_WIDTH; x++)
+ Assert.AreEqual(TestDataHelper.GetColorFromLocation(x, y), testData[(y * TEST_WIDTH) + x]);
+ }
+
+ [TestMethod]
+ public void SubImage()
+ {
+ RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
+ RefImage subImage = image[10, 20, 100, 200];
+
+ for (int y = 0; y < 200; y++)
+ for (int x = 0; x < 100; x++)
+ Assert.AreEqual(TestDataHelper.GetColorFromLocation(10 + x, 20 + y), subImage[x, y]);
+ }
+
+ [TestMethod]
+ public unsafe void Pin()
+ {
+ RefImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
+ ColorARGB[] reference = TestDataHelper.GetPixelData(TEST_WIDTH, TEST_HEIGHT);
+
+ fixed (byte* ptr = image)
+ {
+ for (int i = 0; i < reference.Length; i++)
+ {
+ Assert.AreEqual(reference[i].A, ptr[(i * 4) + 0]);
+ Assert.AreEqual(reference[i].R, ptr[(i * 4) + 1]);
+ Assert.AreEqual(reference[i].G, ptr[(i * 4) + 2]);
+ Assert.AreEqual(reference[i].B, ptr[(i * 4) + 3]);
+ }
+ }
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/HPPH.Test/PixelHelper/ConvertTests.cs b/HPPH.Test/PixelHelper/ConvertTests.cs
index 3a31004..948db7e 100644
--- a/HPPH.Test/PixelHelper/ConvertTests.cs
+++ b/HPPH.Test/PixelHelper/ConvertTests.cs
@@ -26,10 +26,10 @@ public class ConvertTests
ColorRGB reference = referenceData[i];
ColorBGR test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -56,10 +56,10 @@ public class ConvertTests
ColorRGBA reference = referenceData[i];
ColorARGB test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -86,10 +86,10 @@ public class ConvertTests
ColorRGBA reference = referenceData[i];
ColorBGRA test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -116,10 +116,10 @@ public class ConvertTests
ColorRGBA reference = referenceData[i];
ColorRGB test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(255, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -146,10 +146,10 @@ public class ConvertTests
ColorRGBA reference = referenceData[i];
ColorBGR test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(255, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -176,10 +176,10 @@ public class ConvertTests
ColorRGB reference = referenceData[i];
ColorRGBA test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -206,10 +206,10 @@ public class ConvertTests
ColorRGB reference = referenceData[i];
ColorARGB test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -236,10 +236,10 @@ public class ConvertTests
ColorRGB reference = referenceData[i];
ColorBGRA test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
@@ -266,10 +266,10 @@ public class ConvertTests
ColorRGB reference = referenceData[i];
ColorABGR test = result[i];
- Assert.AreEqual(reference.R, test.R, $"R differs at index {i}");
- Assert.AreEqual(reference.G, test.G, $"G differs at index {i}");
- Assert.AreEqual(reference.B, test.B, $"B differs at index {i}");
- Assert.AreEqual(reference.A, test.A, $"A differs at index {i}");
+ Assert.AreEqual(reference.R, test.R, $"R differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.G, test.G, $"G differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.B, test.B, $"B differs at index {i}. Image: {image}, skip: {skip}");
+ Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
}
}
}
diff --git a/HPPH.Test/PixelHelper/QuantizeTests.cs b/HPPH.Test/PixelHelper/QuantizeTests.cs
index d081189..08bba5b 100644
--- a/HPPH.Test/PixelHelper/QuantizeTests.cs
+++ b/HPPH.Test/PixelHelper/QuantizeTests.cs
@@ -7,111 +7,196 @@ public class CreateColorPaletteTests
{
private static IEnumerable GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
- [TestMethod]
- public void CreateColorPaletteReadOnlySpan3ByteSize1()
+ private static int[] Sizes => [0, 1, 2, 16, 64];
+
+ private static readonly Dictionary>> _reference = [];
+
+ [ClassInitialize]
+ public static void Initialize(TestContext context)
{
+ ReadOnlySpan sizes = Sizes;
foreach (string image in GetTestImages())
{
- ColorRGB[] data = ImageHelper.GetColorsFromImage(image);
- Span span = data;
+ _reference[image] = [];
- ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- ColorRGB[] test = [.. span.CreateColorPalette(1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
-
- Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
-
- for (int i = 0; i < reference.Length; i++)
- Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
+ Initialize(image, sizes);
+ Initialize(image, sizes);
+ Initialize(image, sizes);
+ Initialize(image, sizes);
+ Initialize(image, sizes);
+ Initialize(image, sizes);
}
}
- [TestMethod]
- public void CreateColorPaletteReadOnlySpan3ByteSize4()
+ private static void Initialize(string image, ReadOnlySpan sizes)
+ where T : unmanaged, IColor
{
- foreach (string image in GetTestImages())
- {
- ColorRGB[] data = ImageHelper.GetColorsFromImage(image);
- Span span = data;
+ _reference[image][typeof(T)] = [];
- ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- ColorRGB[] test = [.. span.CreateColorPalette(2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
-
- Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
-
- for (int i = 0; i < reference.Length; i++)
- Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
- }
+ Image img = ImageHelper.GetImage(image);
+ foreach (int size in sizes)
+ _reference[image][typeof(T)][size] = [.. ReferencePixelHelper.CreateColorPalette(img, size).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
}
[TestMethod]
- public void CreateColorPaletteReadOnlySpan3ByteSize16()
+ public void CreateColorPaletteReadOnlySpan()
{
+ ReadOnlySpan sizes = Sizes;
foreach (string image in GetTestImages())
{
- ColorRGB[] data = ImageHelper.GetColorsFromImage(image);
- Span span = data;
-
- ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- ColorRGB[] test = [.. span.CreateColorPalette(16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
-
- Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
-
- for (int i = 0; i < reference.Length; i++)
- Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
+ foreach (int size in sizes)
+ {
+ CreateColorPaletteReadOnlySpan(image, size);
+ CreateColorPaletteReadOnlySpan(image, size);
+ CreateColorPaletteReadOnlySpan(image, size);
+ CreateColorPaletteReadOnlySpan(image, size);
+ CreateColorPaletteReadOnlySpan(image, size);
+ CreateColorPaletteReadOnlySpan(image, size);
+ }
}
}
- [TestMethod]
- public void CreateColorPaletteReadOnlySpan4ByteSize1()
+ private void CreateColorPaletteReadOnlySpan(string image, int size)
+ where T : unmanaged, IColor
{
- foreach (string image in GetTestImages())
- {
- ColorRGBA[] data = ImageHelper.GetColorsFromImage(image);
- Span span = data;
+ T[] data = ImageHelper.GetColorsFromImage(image);
+ ReadOnlySpan span = data;
- ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- ColorRGBA[] test = [.. span.CreateColorPalette(1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
+ T[] test = [.. span.CreateColorPalette(size).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
+ IColor[] reference = _reference[image][typeof(T)][size];
+ Assert.AreEqual(reference.Length, test.Length, $"Palette Size differs for image {image}, size {size}");
- for (int i = 0; i < reference.Length; i++)
- Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
- }
+ for (int i = 0; i < reference.Length; i++)
+ Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
}
[TestMethod]
- public void CreateColorPaletteReadOnlySpan4ByteSize4()
+ public void CreateColorPaletteSpan()
{
+ ReadOnlySpan sizes = Sizes;
foreach (string image in GetTestImages())
{
- ColorRGBA[] data = ImageHelper.GetColorsFromImage(image);
- Span span = data;
-
- ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- ColorRGBA[] test = [.. span.CreateColorPalette(2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
-
- Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
-
- for (int i = 0; i < reference.Length; i++)
- Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
+ foreach (int size in sizes)
+ {
+ CreateColorPaletteSpan(image, size);
+ CreateColorPaletteSpan(image, size);
+ CreateColorPaletteSpan(image, size);
+ CreateColorPaletteSpan(image, size);
+ CreateColorPaletteSpan(image, size);
+ CreateColorPaletteSpan(image, size);
+ }
}
}
- [TestMethod]
- public void CreateColorPaletteReadOnlySpan4ByteSize16()
+ private void CreateColorPaletteSpan(string image, int size)
+ where T : unmanaged, IColor
{
+ T[] data = ImageHelper.GetColorsFromImage(image);
+ Span span = data;
+
+ T[] test = [.. span.CreateColorPalette(size).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
+
+ IColor[] reference = _reference[image][typeof(T)][size];
+ Assert.AreEqual(reference.Length, test.Length, $"Palette Size differs for image {image}, size {size}");
+
+ for (int i = 0; i < reference.Length; i++)
+ Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
+ }
+
+ [TestMethod]
+ public void CreateColorPaletteImage()
+ {
+ ReadOnlySpan sizes = Sizes;
foreach (string image in GetTestImages())
{
- ColorRGBA[] data = ImageHelper.GetColorsFromImage(image);
- Span span = data;
-
- ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
- ColorRGBA[] test = [.. span.CreateColorPalette(16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
-
- Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
-
- for (int i = 0; i < reference.Length; i++)
- Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
+ foreach (int size in sizes)
+ {
+ CreateColorPaletteImage(image, size);
+ CreateColorPaletteImage(image, size);
+ CreateColorPaletteImage(image, size);
+ CreateColorPaletteImage(image, size);
+ CreateColorPaletteImage(image, size);
+ CreateColorPaletteImage(image, size);
+ }
}
}
+
+ private void CreateColorPaletteImage(string image, int size)
+ where T : struct, IColor
+ {
+ IImage data = ImageHelper.GetImage(image);
+
+ IColor[] test = [.. data.CreateColorPalette(size).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
+
+ IColor[] reference = _reference[image][typeof(T)][size];
+ Assert.AreEqual(reference.Length, test.Length, $"Palette Size differs for image {image}, size {size}");
+
+ for (int i = 0; i < reference.Length; i++)
+ Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
+ }
+
+ [TestMethod]
+ public void CreateColorPaletteGenericImage()
+ {
+ ReadOnlySpan sizes = Sizes;
+ foreach (string image in GetTestImages())
+ {
+ foreach (int size in sizes)
+ {
+ CreateColorPaletteGenericImage(image, size);
+ CreateColorPaletteGenericImage(image, size);
+ CreateColorPaletteGenericImage(image, size);
+ CreateColorPaletteGenericImage(image, size);
+ CreateColorPaletteGenericImage(image, size);
+ CreateColorPaletteGenericImage(image, size);
+ }
+ }
+ }
+
+ private void CreateColorPaletteGenericImage(string image, int size)
+ where T : unmanaged, IColor
+ {
+ Image data = ImageHelper.GetImage(image);
+
+ T[] test = [.. data.CreateColorPalette(size).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
+
+ IColor[] reference = _reference[image][typeof(T)][size];
+ Assert.AreEqual(reference.Length, test.Length, $"Palette Size differs for image {image}, size {size}");
+
+ for (int i = 0; i < reference.Length; i++)
+ Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
+ }
+
+ [TestMethod]
+ public void CreateColorPaletteRefImage()
+ {
+ ReadOnlySpan sizes = Sizes;
+ foreach (string image in GetTestImages())
+ {
+ foreach (int size in sizes)
+ {
+ CreateColorPaletteRefImage(image, size);
+ CreateColorPaletteRefImage(image, size);
+ CreateColorPaletteRefImage(image, size);
+ CreateColorPaletteRefImage(image, size);
+ CreateColorPaletteRefImage(image, size);
+ CreateColorPaletteRefImage(image, size);
+ }
+ }
+ }
+
+ private void CreateColorPaletteRefImage(string image, int size)
+ where T : unmanaged, IColor
+ {
+ RefImage data = ImageHelper.GetImage(image).AsRefImage();
+
+ T[] test = [.. data.CreateColorPalette(size).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
+
+ IColor[] reference = _reference[image][typeof(T)][size];
+ Assert.AreEqual(reference.Length, test.Length, $"Palette Size differs for image {image}, size {size}");
+
+ for (int i = 0; i < reference.Length; i++)
+ Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
+ }
}
\ No newline at end of file
diff --git a/HPPH/Colors/IColor.cs b/HPPH/Colors/IColor.cs
index 82d5a29..740a036 100644
--- a/HPPH/Colors/IColor.cs
+++ b/HPPH/Colors/IColor.cs
@@ -3,7 +3,7 @@
///
/// Represents a generic color made of 4 bytes (alpha, red, green and blue)
///
-public interface IColor
+public interface IColor : IEquatable
{
///
/// Gets the red-component of this color.
diff --git a/HPPH/Data/Generic3ByteMinMax.cs b/HPPH/Data/Generic3ByteMinMax.cs
index c4a226a..4e808b0 100644
--- a/HPPH/Data/Generic3ByteMinMax.cs
+++ b/HPPH/Data/Generic3ByteMinMax.cs
@@ -13,8 +13,4 @@ internal readonly struct Generic3ByteMinMax(byte b1Min, byte b1Max, byte b2Min,
public readonly byte B3Min = b3Min;
public readonly byte B3Max = b3Max;
-
- public byte B1Range => (byte)(B1Max - B1Min);
- public byte B2Range => (byte)(B2Max - B2Min);
- public byte B3Range => (byte)(B3Max - B3Min);
}
diff --git a/HPPH/Data/Generic4ByteMinMax.cs b/HPPH/Data/Generic4ByteMinMax.cs
index 09b191f..d971c15 100644
--- a/HPPH/Data/Generic4ByteMinMax.cs
+++ b/HPPH/Data/Generic4ByteMinMax.cs
@@ -16,9 +16,4 @@ internal readonly struct Generic4ByteMinMax(byte b1Min, byte b1Max, byte b2Min,
public readonly byte B4Min = b4Min;
public readonly byte B4Max = b4Max;
-
- public byte B1Range => (byte)(B1Max - B1Min);
- public byte B2Range => (byte)(B2Max - B2Min);
- public byte B3Range => (byte)(B3Max - B3Min);
- public byte B4Range => (byte)(B4Max - B4Min);
}
diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorABGR.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorABGR.g.cs
index a652165..749268b 100644
--- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorABGR.g.cs
+++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorABGR.g.cs
@@ -49,6 +49,9 @@ public readonly partial struct ColorABGR(byte a, byte b, byte g, byte r) : IColo
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorARGB.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorARGB.g.cs
index 2c1950f..04eef35 100644
--- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorARGB.g.cs
+++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorARGB.g.cs
@@ -49,6 +49,9 @@ public readonly partial struct ColorARGB(byte a, byte r, byte g, byte b) : IColo
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGR.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGR.g.cs
index 8d75a41..72080cc 100644
--- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGR.g.cs
+++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGR.g.cs
@@ -47,6 +47,9 @@ public readonly partial struct ColorBGR(byte b, byte g, byte r): IColor
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGRA.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGRA.g.cs
index 70d5d72..8c449e5 100644
--- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGRA.g.cs
+++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorBGRA.g.cs
@@ -49,6 +49,9 @@ public readonly partial struct ColorBGRA(byte b, byte g, byte r, byte a) : IColo
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGB.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGB.g.cs
index 6746521..0115749 100644
--- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGB.g.cs
+++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGB.g.cs
@@ -47,6 +47,9 @@ public readonly partial struct ColorRGB(byte r, byte g, byte b): IColor
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGBA.g.cs b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGBA.g.cs
index 07f9997..c30acf5 100644
--- a/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGBA.g.cs
+++ b/HPPH/Generated/HPPH.Generators/HPPH.Generators.ColorSourceGenerator/ColorRGBA.g.cs
@@ -49,6 +49,9 @@ public readonly partial struct ColorRGBA(byte r, byte g, byte b, byte a) : IColo
#region Methods
+ ///
+ public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
+
///
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
diff --git a/HPPH/Images/Interfaces/IImageRow.cs b/HPPH/Images/Interfaces/IImageRow.cs
index 5e6b681..ae15708 100644
--- a/HPPH/Images/Interfaces/IImageRow.cs
+++ b/HPPH/Images/Interfaces/IImageRow.cs
@@ -22,6 +22,8 @@ public interface IImageRow : IEnumerable
/// The at the specified location.
IColor this[int x] { get; }
+ void CopyTo(Span destination);
+
///
/// Copies the contents of this into a destination instance.
///
diff --git a/HPPH/PixelHelper.Quantize.cs b/HPPH/PixelHelper.Quantize.cs
index 1bfdc12..beb83ce 100644
--- a/HPPH/PixelHelper.Quantize.cs
+++ b/HPPH/PixelHelper.Quantize.cs
@@ -66,6 +66,9 @@ public static partial class PixelHelper
public static T[] CreateColorPalette(this Span colors, int paletteSize)
where T : unmanaged, IColor
{
+ if (paletteSize < 0) throw new ArgumentException("PaletteSize Can't be < 0", nameof(paletteSize));
+ if (paletteSize == 0) return [];
+
int splits = BitOperations.Log2((uint)paletteSize);
Span> cubes = new ColorCube[1 << splits];
diff --git a/sample_data/1.png b/sample_data/1.png
index d366d84..b452e5c 100644
Binary files a/sample_data/1.png and b/sample_data/1.png differ
diff --git a/sample_data/3.png b/sample_data/3.png
index c6049ad..e851411 100644
Binary files a/sample_data/3.png and b/sample_data/3.png differ
diff --git a/sample_data/4.png b/sample_data/4.png
index a8c8a29..f0d0608 100644
Binary files a/sample_data/4.png and b/sample_data/4.png differ
diff --git a/sample_data/5.png b/sample_data/5.png
index 47637ad..7bcf1e8 100644
Binary files a/sample_data/5.png and b/sample_data/5.png differ
diff --git a/sample_data/6.png b/sample_data/6.png
new file mode 100644
index 0000000..9d45a6a
Binary files /dev/null and b/sample_data/6.png differ
diff --git a/sample_data/7.png b/sample_data/7.png
new file mode 100644
index 0000000..b01460e
Binary files /dev/null and b/sample_data/7.png differ
diff --git a/sample_data/8.png b/sample_data/8.png
new file mode 100644
index 0000000..19a9ac3
Binary files /dev/null and b/sample_data/8.png differ
diff --git a/sample_data/9.png b/sample_data/9.png
new file mode 100644
index 0000000..5514ad4
Binary files /dev/null and b/sample_data/9.png differ