diff --git a/HPPH.Test/Image/ImageTest.cs b/HPPH.Test/Image/ImageTest.cs index cf4731a..c0ad725 100644 --- a/HPPH.Test/Image/ImageTest.cs +++ b/HPPH.Test/Image/ImageTest.cs @@ -158,5 +158,51 @@ public class ImageTest Assert.AreEqual(image[x, y], refImage[x, y]); } + [TestMethod] + public void ConvertToInPlace() + { + IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT); + + IColor[] referenceData = image.ToArray(); + + image.ConvertTo(); + IColor[] testData = image.ToArray(); + + Assert.AreEqual(referenceData.Length, testData.Length); + for (int i = 0; i < referenceData.Length; i++) + { + IColor reference = referenceData[i]; + IColor test = testData[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}"); + } + } + + [TestMethod] + public void ConvertToCopy() + { + IImage image = TestDataHelper.CreateTestImage(TEST_WIDTH, TEST_HEIGHT); + + IColor[] referenceData = image.ToArray(); + + image.ConvertTo(); + IColor[] testData = image.ToArray(); + + Assert.AreEqual(referenceData.Length, testData.Length); + for (int i = 0; i < referenceData.Length; i++) + { + IColor reference = referenceData[i]; + IColor test = testData[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}"); + } + } + #endregion } \ No newline at end of file diff --git a/HPPH/Images/Image.cs b/HPPH/Images/Image.cs index fb28136..2d6f8f2 100644 --- a/HPPH/Images/Image.cs +++ b/HPPH/Images/Image.cs @@ -51,7 +51,6 @@ public sealed class Image : IImage } } - IImage IImage.this[int x, int y, int width, int height] { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -123,11 +122,23 @@ public sealed class Image : IImage return new Image(data, 0, 0, width, height, stride); } - public void ConvertTo() + public IImage ConvertTo() where TColor : struct, IColor { - for (int i = 0; i < Height; i++) - MemoryMarshal.Cast(_buffer.AsSpan().Slice(((i + _y) * _stride) + _x, Width)).ConvertInPlace(); + int targetBpp = TColor.ColorFormat.BytesPerPixel; + if (targetBpp == ColorFormat.BytesPerPixel) + { + byte[] data = ToRawArray(); + MemoryMarshal.Cast(data.AsSpan()).ConvertInPlace(); + return new Image(data, 0, 0, Width, Height, Width * targetBpp); + } + else + { + byte[] data = ToRawArray(); + byte[] target = new byte[Width * Height * targetBpp]; + MemoryMarshal.Cast(data.AsSpan()).Convert(MemoryMarshal.Cast(target)); + return new Image(target, 0, 0, Width, Height, Width * targetBpp); + } } public void CopyTo(Span destination) => CopyTo(MemoryMarshal.AsBytes(destination)); diff --git a/HPPH/Images/Interfaces/IImage.cs b/HPPH/Images/Interfaces/IImage.cs index 75d019b..ec312d4 100644 --- a/HPPH/Images/Interfaces/IImage.cs +++ b/HPPH/Images/Interfaces/IImage.cs @@ -60,8 +60,8 @@ public interface IImage : IEnumerable /// The . RefImage AsRefImage() where TColor : struct, IColor; - void ConvertTo() where T : struct, IColor; - + IImage ConvertTo() where TColor : struct, IColor; + /// /// Copies the contents of this into a destination instance. /// diff --git a/HPPH/PixelHelper.Convert.cs b/HPPH/PixelHelper.Convert.cs index 405ab26..c156a1f 100644 --- a/HPPH/PixelHelper.Convert.cs +++ b/HPPH/PixelHelper.Convert.cs @@ -33,7 +33,7 @@ public static unsafe partial class PixelHelper if (colors == null) throw new ArgumentNullException(nameof(colors)); TTarget[] buffer = new TTarget[colors.Length]; - Convert(colors, buffer.AsSpan()); + Convert(colors, buffer.AsSpan()); return buffer; } @@ -48,6 +48,17 @@ public static unsafe partial class PixelHelper return buffer; } + public static void Convert(this Span source, Span target) + where TSource : struct, IColor + where TTarget : struct, IColor + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (target == null) throw new ArgumentNullException(nameof(target)); + if (target.Length < source.Length) throw new ArgumentException($"Target-buffer is not big enough. {target.Length} < {source.Length}", nameof(target)); + + Convert(MemoryMarshal.AsBytes(source), MemoryMarshal.AsBytes(target), TSource.ColorFormat, TTarget.ColorFormat); + } + public static void Convert(this ReadOnlySpan source, Span target) where TSource : struct, IColor where TTarget : struct, IColor