Made colors equatable; added more tests; small improvements; changed test-data to cover more edge-cases
@ -74,6 +74,9 @@ internal class Colors : IGeneratorFeature
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
@ -137,6 +140,9 @@ internal class Colors : IGeneratorFeature
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,9 @@ public static partial class ReferencePixelHelper
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public static IColor[] CreateColorPalette(IImage image, int paletteSize)
|
public static T[] CreateColorPalette<T>(Image<T> image, int paletteSize)
|
||||||
=> CreateColorPalette(image.ToArray(), paletteSize);
|
where T : unmanaged, IColor
|
||||||
|
=> CreateColorPalette<T>(image.ToArray(), paletteSize);
|
||||||
|
|
||||||
public static T[] CreateColorPalette<T>(RefImage<T> image, int paletteSize)
|
public static T[] CreateColorPalette<T>(RefImage<T> image, int paletteSize)
|
||||||
where T : unmanaged, IColor
|
where T : unmanaged, IColor
|
||||||
@ -15,17 +16,20 @@ public static partial class ReferencePixelHelper
|
|||||||
|
|
||||||
public static T[] CreateColorPalette<T>(Span<T> colors, int paletteSize)
|
public static T[] CreateColorPalette<T>(Span<T> colors, int paletteSize)
|
||||||
where T : unmanaged, IColor =>
|
where T : unmanaged, IColor =>
|
||||||
CreateColorPalette(colors.ToArray().Cast<IColor>().ToArray(), paletteSize).Select(x => T.Create(x.R, x.G, x.B, x.A)).Cast<T>().ToArray();
|
CreateColorPalette<T>(colors.ToArray().Cast<IColor>().ToArray(), paletteSize).Select(x => T.Create(x.R, x.G, x.B, x.A)).Cast<T>().ToArray();
|
||||||
|
|
||||||
private static IColor[] CreateColorPalette(IColor[] colors, int paletteSize)
|
private static IColor[] CreateColorPalette<T>(IColor[] colors, int paletteSize)
|
||||||
|
where T : struct, IColor
|
||||||
{
|
{
|
||||||
|
if (paletteSize == 0) return [];
|
||||||
|
|
||||||
int splits = BitOperations.Log2((uint)paletteSize);
|
int splits = BitOperations.Log2((uint)paletteSize);
|
||||||
|
|
||||||
List<ColorCube> cubes = [new ColorCube(colors)];
|
HashSet<ColorCube> cubes = [new ColorCube(colors)];
|
||||||
|
|
||||||
for (int i = 0; i < splits; i++)
|
for (int i = 0; i < splits; i++)
|
||||||
{
|
{
|
||||||
List<ColorCube> currentCubes = [.. cubes];
|
HashSet<ColorCube> currentCubes = [.. cubes];
|
||||||
foreach (ColorCube currentCube in currentCubes)
|
foreach (ColorCube currentCube in currentCubes)
|
||||||
{
|
{
|
||||||
currentCube.Split(out ColorCube a, out ColorCube b);
|
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<T>()).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -53,6 +57,12 @@ internal class ColorCube
|
|||||||
|
|
||||||
internal ColorCube(IList<IColor> colors)
|
internal ColorCube(IList<IColor> colors)
|
||||||
{
|
{
|
||||||
|
if (colors.Count == 0)
|
||||||
|
{
|
||||||
|
_colors = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int redRange = colors.Max(c => c.R) - colors.Min(c => c.R);
|
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 greenRange = colors.Max(c => c.G) - colors.Min(c => c.G);
|
||||||
int blueRange = colors.Max(c => c.B) - colors.Min(c => c.B);
|
int blueRange = colors.Max(c => c.B) - colors.Min(c => c.B);
|
||||||
@ -77,14 +87,17 @@ internal class ColorCube
|
|||||||
b = new ColorCube(_colors.GetRange(median, _colors.Count - median));
|
b = new ColorCube(_colors.GetRange(median, _colors.Count - median));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IColor GetAverageColor()
|
internal IColor GetAverageColor<T>()
|
||||||
|
where T : struct, IColor
|
||||||
{
|
{
|
||||||
|
if (_colors.Count == 0) return T.Create(0, 0, 0, 0);
|
||||||
|
|
||||||
int r = _colors.Sum(x => x.R);
|
int r = _colors.Sum(x => x.R);
|
||||||
int g = _colors.Sum(x => x.G);
|
int g = _colors.Sum(x => x.G);
|
||||||
int b = _colors.Sum(x => x.B);
|
int b = _colors.Sum(x => x.B);
|
||||||
int a = _colors.Sum(x => x.A);
|
int a = _colors.Sum(x => x.A);
|
||||||
|
|
||||||
return new ColorRGBA((byte)(r / _colors.Count),
|
return T.Create((byte)(r / _colors.Count),
|
||||||
(byte)(g / _colors.Count),
|
(byte)(g / _colors.Count),
|
||||||
(byte)(b / _colors.Count),
|
(byte)(b / _colors.Count),
|
||||||
(byte)(a / _colors.Count));
|
(byte)(a / _colors.Count));
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using System.Runtime.InteropServices;
|
namespace HPPH.Test.Colors;
|
||||||
|
|
||||||
namespace HPPH.Test.Colors;
|
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class MinMaxStructTests
|
public class MinMaxStructTests
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public class ImageTest
|
|||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageCreation()
|
public void ImageCreation()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageInnerFull()
|
public void ImageInnerFull()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
image = image[0, 0, image.Width, image.Height];
|
image = image[0, 0, image.Width, image.Height];
|
||||||
@ -39,7 +39,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageEnumerator()
|
public void ImageEnumerator()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageInnerPartial()
|
public void ImageInnerPartial()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
image = image[163, 280, 720, 13];
|
image = image[163, 280, 720, 13];
|
||||||
@ -70,7 +70,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageInnerInnerPartial()
|
public void ImageInnerInnerPartial()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
image = image[163, 280, 720, 13];
|
image = image[163, 280, 720, 13];
|
||||||
@ -85,7 +85,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageRowIndexer()
|
public void ImageRowIndexer()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageRowEnumerator()
|
public void ImageRowEnumerator()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageColumnIndexer()
|
public void ImageColumnIndexer()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageColumnEnumerator()
|
public void ImageColumnEnumerator()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestAsRefImage()
|
public void AsRefImage()
|
||||||
{
|
{
|
||||||
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT);
|
||||||
image = image[163, 280, 720, 13];
|
image = image[163, 280, 720, 13];
|
||||||
@ -417,6 +417,16 @@ public class ImageTest
|
|||||||
|
|
||||||
y++;
|
y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
y = 0;
|
||||||
|
foreach (IImageRow row in (IEnumerable)image.Rows)
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
foreach (IColor color in (IEnumerable)row)
|
||||||
|
Assert.AreEqual(TestDataHelper.GetColorFromLocation<ColorARGB>(x++, y), color);
|
||||||
|
|
||||||
|
y++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -509,5 +519,53 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void InterfaceRowsCopyTo()
|
||||||
|
{
|
||||||
|
IImage image = TestDataHelper.CreateTestImage<ColorARGB>(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<ColorARGB>(x++, y), color);
|
||||||
|
|
||||||
|
for (x = 0; x < TEST_WIDTH; x++)
|
||||||
|
{
|
||||||
|
IColor reference = TestDataHelper.GetColorFromLocation<ColorARGB>(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<ColorARGB>(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<ColorARGB>(x, y), data[x]);
|
||||||
|
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@ public class RefImageTest
|
|||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageCreation()
|
public void ImageCreation()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageInnerFull()
|
public void ImageInnerFull()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
image = image[0, 0, image.Width, image.Height];
|
image = image[0, 0, image.Width, image.Height];
|
||||||
@ -39,7 +39,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageEnumerator()
|
public void ImageEnumerator()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ public class RefImageTest
|
|||||||
int x = counter % image.Width;
|
int x = counter % image.Width;
|
||||||
int y = counter / image.Width;
|
int y = counter / image.Width;
|
||||||
|
|
||||||
if(y == 1) Debugger.Break();
|
if (y == 1) Debugger.Break();
|
||||||
|
|
||||||
Assert.AreEqual(TestDataHelper.GetColorFromLocation<ColorARGB>(x, y), color);
|
Assert.AreEqual(TestDataHelper.GetColorFromLocation<ColorARGB>(x, y), color);
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageInnerPartial()
|
public void ImageInnerPartial()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
image = image[163, 280, 720, 13];
|
image = image[163, 280, 720, 13];
|
||||||
@ -72,7 +72,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageInnerInnerPartial()
|
public void ImageInnerInnerPartial()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
image = image[163, 280, 720, 13];
|
image = image[163, 280, 720, 13];
|
||||||
@ -87,7 +87,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageRowIndexer()
|
public void ImageRowIndexer()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageRowEnumerator()
|
public void ImageRowEnumerator()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageColumnIndexer()
|
public void ImageColumnIndexer()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestImageColumnEnumerator()
|
public void ImageColumnEnumerator()
|
||||||
{
|
{
|
||||||
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
|
||||||
@ -148,5 +148,57 @@ public class RefImageTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToArray()
|
||||||
|
{
|
||||||
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(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<ColorARGB>(x, y), testData[(y * TEST_WIDTH) + x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CopyTo()
|
||||||
|
{
|
||||||
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(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<ColorARGB>(x, y), testData[(y * TEST_WIDTH) + x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SubImage()
|
||||||
|
{
|
||||||
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
RefImage<ColorARGB> subImage = image[10, 20, 100, 200];
|
||||||
|
|
||||||
|
for (int y = 0; y < 200; y++)
|
||||||
|
for (int x = 0; x < 100; x++)
|
||||||
|
Assert.AreEqual(TestDataHelper.GetColorFromLocation<ColorARGB>(10 + x, 20 + y), subImage[x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public unsafe void Pin()
|
||||||
|
{
|
||||||
|
RefImage<ColorARGB> image = TestDataHelper.CreateTestImage<ColorARGB>(TEST_WIDTH, TEST_HEIGHT).AsRefImage();
|
||||||
|
ColorARGB[] reference = TestDataHelper.GetPixelData<ColorARGB>(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
|
#endregion
|
||||||
}
|
}
|
||||||
@ -26,10 +26,10 @@ public class ConvertTests
|
|||||||
ColorRGB reference = referenceData[i];
|
ColorRGB reference = referenceData[i];
|
||||||
ColorBGR test = result[i];
|
ColorBGR test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGBA reference = referenceData[i];
|
||||||
ColorARGB test = result[i];
|
ColorARGB test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGBA reference = referenceData[i];
|
||||||
ColorBGRA test = result[i];
|
ColorBGRA test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGBA reference = referenceData[i];
|
||||||
ColorRGB test = result[i];
|
ColorRGB test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGBA reference = referenceData[i];
|
||||||
ColorBGR test = result[i];
|
ColorBGR test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGB reference = referenceData[i];
|
||||||
ColorRGBA test = result[i];
|
ColorRGBA test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGB reference = referenceData[i];
|
||||||
ColorARGB test = result[i];
|
ColorARGB test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGB reference = referenceData[i];
|
||||||
ColorBGRA test = result[i];
|
ColorBGRA test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
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];
|
ColorRGB reference = referenceData[i];
|
||||||
ColorABGR test = result[i];
|
ColorABGR test = result[i];
|
||||||
|
|
||||||
Assert.AreEqual(reference.R, test.R, $"R 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}");
|
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}");
|
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}");
|
Assert.AreEqual(reference.A, test.A, $"A differs at index {i}. Image: {image}, skip: {skip}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,111 +7,196 @@ public class CreateColorPaletteTests
|
|||||||
{
|
{
|
||||||
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
|
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
|
||||||
|
|
||||||
[TestMethod]
|
private static int[] Sizes => [0, 1, 2, 16, 64];
|
||||||
public void CreateColorPaletteReadOnlySpan3ByteSize1()
|
|
||||||
|
private static readonly Dictionary<string, Dictionary<Type, Dictionary<int, IColor[]>>> _reference = [];
|
||||||
|
|
||||||
|
[ClassInitialize]
|
||||||
|
public static void Initialize(TestContext context)
|
||||||
{
|
{
|
||||||
|
ReadOnlySpan<int> sizes = Sizes;
|
||||||
foreach (string image in GetTestImages())
|
foreach (string image in GetTestImages())
|
||||||
{
|
{
|
||||||
ColorRGB[] data = ImageHelper.GetColorsFromImage<ColorRGB>(image);
|
_reference[image] = [];
|
||||||
Span<ColorRGB> span = data;
|
|
||||||
|
|
||||||
ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
Initialize<ColorRGB>(image, sizes);
|
||||||
ColorRGB[] test = [.. span.CreateColorPalette(1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
Initialize<ColorBGR>(image, sizes);
|
||||||
|
Initialize<ColorRGBA>(image, sizes);
|
||||||
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
|
Initialize<ColorBGRA>(image, sizes);
|
||||||
|
Initialize<ColorARGB>(image, sizes);
|
||||||
for (int i = 0; i < reference.Length; i++)
|
Initialize<ColorABGR>(image, sizes);
|
||||||
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Initialize<T>(string image, ReadOnlySpan<int> sizes)
|
||||||
|
where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
_reference[image][typeof(T)] = [];
|
||||||
|
|
||||||
|
Image<T> img = ImageHelper.GetImage<T>(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]
|
[TestMethod]
|
||||||
public void CreateColorPaletteReadOnlySpan3ByteSize4()
|
public void CreateColorPaletteReadOnlySpan()
|
||||||
{
|
{
|
||||||
|
ReadOnlySpan<int> sizes = Sizes;
|
||||||
foreach (string image in GetTestImages())
|
foreach (string image in GetTestImages())
|
||||||
{
|
{
|
||||||
ColorRGB[] data = ImageHelper.GetColorsFromImage<ColorRGB>(image);
|
foreach (int size in sizes)
|
||||||
Span<ColorRGB> span = data;
|
{
|
||||||
|
CreateColorPaletteReadOnlySpan<ColorRGB>(image, size);
|
||||||
|
CreateColorPaletteReadOnlySpan<ColorBGR>(image, size);
|
||||||
|
CreateColorPaletteReadOnlySpan<ColorRGBA>(image, size);
|
||||||
|
CreateColorPaletteReadOnlySpan<ColorBGRA>(image, size);
|
||||||
|
CreateColorPaletteReadOnlySpan<ColorARGB>(image, size);
|
||||||
|
CreateColorPaletteReadOnlySpan<ColorABGR>(image, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
private void CreateColorPaletteReadOnlySpan<T>(string image, int size)
|
||||||
ColorRGB[] test = [.. span.CreateColorPalette(2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
T[] data = ImageHelper.GetColorsFromImage<T>(image);
|
||||||
|
ReadOnlySpan<T> span = data;
|
||||||
|
|
||||||
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
|
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++)
|
for (int i = 0; i < reference.Length; i++)
|
||||||
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
|
Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void CreateColorPaletteReadOnlySpan3ByteSize16()
|
public void CreateColorPaletteSpan()
|
||||||
{
|
{
|
||||||
|
ReadOnlySpan<int> sizes = Sizes;
|
||||||
foreach (string image in GetTestImages())
|
foreach (string image in GetTestImages())
|
||||||
{
|
{
|
||||||
ColorRGB[] data = ImageHelper.GetColorsFromImage<ColorRGB>(image);
|
foreach (int size in sizes)
|
||||||
Span<ColorRGB> span = data;
|
{
|
||||||
|
CreateColorPaletteSpan<ColorRGB>(image, size);
|
||||||
|
CreateColorPaletteSpan<ColorBGR>(image, size);
|
||||||
|
CreateColorPaletteSpan<ColorRGBA>(image, size);
|
||||||
|
CreateColorPaletteSpan<ColorBGRA>(image, size);
|
||||||
|
CreateColorPaletteSpan<ColorARGB>(image, size);
|
||||||
|
CreateColorPaletteSpan<ColorABGR>(image, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
private void CreateColorPaletteSpan<T>(string image, int size)
|
||||||
ColorRGB[] test = [.. span.CreateColorPalette(16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
T[] data = ImageHelper.GetColorsFromImage<T>(image);
|
||||||
|
Span<T> span = data;
|
||||||
|
|
||||||
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
|
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++)
|
for (int i = 0; i < reference.Length; i++)
|
||||||
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
|
Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void CreateColorPaletteReadOnlySpan4ByteSize1()
|
public void CreateColorPaletteImage()
|
||||||
{
|
{
|
||||||
|
ReadOnlySpan<int> sizes = Sizes;
|
||||||
foreach (string image in GetTestImages())
|
foreach (string image in GetTestImages())
|
||||||
{
|
{
|
||||||
ColorRGBA[] data = ImageHelper.GetColorsFromImage<ColorRGBA>(image);
|
foreach (int size in sizes)
|
||||||
Span<ColorRGBA> span = data;
|
{
|
||||||
|
CreateColorPaletteImage<ColorRGB>(image, size);
|
||||||
|
CreateColorPaletteImage<ColorBGR>(image, size);
|
||||||
|
CreateColorPaletteImage<ColorRGBA>(image, size);
|
||||||
|
CreateColorPaletteImage<ColorBGRA>(image, size);
|
||||||
|
CreateColorPaletteImage<ColorARGB>(image, size);
|
||||||
|
CreateColorPaletteImage<ColorABGR>(image, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
private void CreateColorPaletteImage<T>(string image, int size)
|
||||||
ColorRGBA[] test = [.. span.CreateColorPalette(1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
IImage data = ImageHelper.GetImage<T>(image);
|
||||||
|
|
||||||
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
|
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++)
|
for (int i = 0; i < reference.Length; i++)
|
||||||
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
|
Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void CreateColorPaletteReadOnlySpan4ByteSize4()
|
public void CreateColorPaletteGenericImage()
|
||||||
{
|
{
|
||||||
|
ReadOnlySpan<int> sizes = Sizes;
|
||||||
foreach (string image in GetTestImages())
|
foreach (string image in GetTestImages())
|
||||||
{
|
{
|
||||||
ColorRGBA[] data = ImageHelper.GetColorsFromImage<ColorRGBA>(image);
|
foreach (int size in sizes)
|
||||||
Span<ColorRGBA> span = data;
|
{
|
||||||
|
CreateColorPaletteGenericImage<ColorRGB>(image, size);
|
||||||
|
CreateColorPaletteGenericImage<ColorBGR>(image, size);
|
||||||
|
CreateColorPaletteGenericImage<ColorRGBA>(image, size);
|
||||||
|
CreateColorPaletteGenericImage<ColorBGRA>(image, size);
|
||||||
|
CreateColorPaletteGenericImage<ColorARGB>(image, size);
|
||||||
|
CreateColorPaletteGenericImage<ColorABGR>(image, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
private void CreateColorPaletteGenericImage<T>(string image, int size)
|
||||||
ColorRGBA[] test = [.. span.CreateColorPalette(2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
Image<T> data = ImageHelper.GetImage<T>(image);
|
||||||
|
|
||||||
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
|
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++)
|
for (int i = 0; i < reference.Length; i++)
|
||||||
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
|
Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void CreateColorPaletteReadOnlySpan4ByteSize16()
|
public void CreateColorPaletteRefImage()
|
||||||
{
|
{
|
||||||
|
ReadOnlySpan<int> sizes = Sizes;
|
||||||
foreach (string image in GetTestImages())
|
foreach (string image in GetTestImages())
|
||||||
{
|
{
|
||||||
ColorRGBA[] data = ImageHelper.GetColorsFromImage<ColorRGBA>(image);
|
foreach (int size in sizes)
|
||||||
Span<ColorRGBA> span = data;
|
{
|
||||||
|
CreateColorPaletteRefImage<ColorRGB>(image, size);
|
||||||
|
CreateColorPaletteRefImage<ColorBGR>(image, size);
|
||||||
|
CreateColorPaletteRefImage<ColorRGBA>(image, size);
|
||||||
|
CreateColorPaletteRefImage<ColorBGRA>(image, size);
|
||||||
|
CreateColorPaletteRefImage<ColorARGB>(image, size);
|
||||||
|
CreateColorPaletteRefImage<ColorABGR>(image, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
private void CreateColorPaletteRefImage<T>(string image, int size)
|
||||||
ColorRGBA[] test = [.. span.CreateColorPalette(16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
|
where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
RefImage<T> data = ImageHelper.GetImage<T>(image).AsRefImage();
|
||||||
|
|
||||||
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
|
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++)
|
for (int i = 0; i < reference.Length; i++)
|
||||||
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
|
Assert.AreEqual(reference[i], test[i], $"Index {i} differs for image {image}, size {size}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a generic color made of 4 bytes (alpha, red, green and blue)
|
/// Represents a generic color made of 4 bytes (alpha, red, green and blue)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IColor
|
public interface IColor : IEquatable<IColor>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the red-component of this color.
|
/// Gets the red-component of this color.
|
||||||
|
|||||||
@ -13,8 +13,4 @@ internal readonly struct Generic3ByteMinMax(byte b1Min, byte b1Max, byte b2Min,
|
|||||||
|
|
||||||
public readonly byte B3Min = b3Min;
|
public readonly byte B3Min = b3Min;
|
||||||
public readonly byte B3Max = b3Max;
|
public readonly byte B3Max = b3Max;
|
||||||
|
|
||||||
public byte B1Range => (byte)(B1Max - B1Min);
|
|
||||||
public byte B2Range => (byte)(B2Max - B2Min);
|
|
||||||
public byte B3Range => (byte)(B3Max - B3Min);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,9 +16,4 @@ internal readonly struct Generic4ByteMinMax(byte b1Min, byte b1Max, byte b2Min,
|
|||||||
|
|
||||||
public readonly byte B4Min = b4Min;
|
public readonly byte B4Min = b4Min;
|
||||||
public readonly byte B4Max = b4Max;
|
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,9 @@ public readonly partial struct ColorABGR(byte a, byte b, byte g, byte r) : IColo
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,9 @@ public readonly partial struct ColorARGB(byte a, byte r, byte g, byte b) : IColo
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,9 @@ public readonly partial struct ColorBGR(byte b, byte g, byte r): IColor
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,9 @@ public readonly partial struct ColorBGRA(byte b, byte g, byte r, byte a) : IColo
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,9 @@ public readonly partial struct ColorRGB(byte r, byte g, byte b): IColor
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,9 @@ public readonly partial struct ColorRGBA(byte r, byte g, byte b, byte a) : IColo
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(IColor? other) => (other != null) && (R == other.R) && (G == other.G) && (B == other.B) && (A == other.A);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,8 @@ public interface IImageRow : IEnumerable<IColor>
|
|||||||
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
||||||
IColor this[int x] { get; }
|
IColor this[int x] { get; }
|
||||||
|
|
||||||
|
void CopyTo(Span<IColor> destination);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies the contents of this <see cref="IImageRow"/> into a destination <see cref="Span{T}"/> instance.
|
/// Copies the contents of this <see cref="IImageRow"/> into a destination <see cref="Span{T}"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -66,6 +66,9 @@ public static partial class PixelHelper
|
|||||||
public static T[] CreateColorPalette<T>(this Span<T> colors, int paletteSize)
|
public static T[] CreateColorPalette<T>(this Span<T> colors, int paletteSize)
|
||||||
where T : unmanaged, IColor
|
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);
|
int splits = BitOperations.Log2((uint)paletteSize);
|
||||||
|
|
||||||
Span<ColorCube<T>> cubes = new ColorCube<T>[1 << splits];
|
Span<ColorCube<T>> cubes = new ColorCube<T>[1 << splits];
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 843 KiB |
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 477 KiB |
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 5.9 KiB |
BIN
sample_data/6.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
sample_data/7.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
sample_data/8.png
Normal file
|
After Width: | Height: | Size: 72 B |
BIN
sample_data/9.png
Normal file
|
After Width: | Height: | Size: 69 B |