From 6c5c2a5cd1c90634d43efa4746d3e3ac2e04ef3d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 14 Jun 2018 00:36:02 +1000 Subject: [PATCH] Read Rgba64 png + some tests --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 37 +++++----- .../PixelOperations{TPixel}.Generated.cs | 71 +++++++++++++++++++ .../PixelOperations{TPixel}.Generated.tt | 45 ++++++++++++ .../PixelFormats/Alpha8Tests.cs | 33 +++++++++ .../PixelFormats/Argb32Tests.cs | 16 +++++ .../PixelFormats/Bgr24Tests.cs | 20 +++++- .../PixelFormats/Bgr565Tests.cs | 18 ++++- .../PixelFormats/Bgra32Tests.cs | 18 ++++- .../PixelFormats/Bgra4444Tests.cs | 16 +++++ 9 files changed, 249 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index cc98b8450b..c122aa4046 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -784,12 +784,15 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.header.BitDepth == 16) { - int length = this.header.Width * 4; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < this.header.Width; x++, o += 8) { - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); - PixelOperations.Instance.PackFromRgba32Bytes(compressed.Span, rowSpan, this.header.Width); + rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2)); + color.PackFromRgba64(rgba64); + rowSpan[x] = color; } } else @@ -1053,23 +1056,15 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.header.BitDepth == 16) { - int length = this.header.Width * 4; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 8) { - Span compressedSpan = compressed.Span; - - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length); - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) - { - rgba.R = compressedSpan[o]; - rgba.G = compressedSpan[o + 1]; - rgba.B = compressedSpan[o + 2]; - rgba.A = compressedSpan[o + 3]; - - color.PackFromRgba32(rgba); - rowSpan[x] = color; - } + rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2)); + color.PackFromRgba64(rgba64); + rowSpan[x] = color; } } else diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 025204c894..2656f9a3a7 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -11,6 +11,77 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + var rgba = new Rgba64(0, 0, 0, 65535); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + rgba = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba64(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToRgba64(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + { + this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); + } + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 060973c744..f73f37eb86 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -51,6 +51,48 @@ <# } + void GeneratePackFromMethodUsingPackFromRgba64(string pixelType, string rgbaOperationCode) + { + #> + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + var rgba = new Rgba64(0, 0, 0, 65535); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + <#=rgbaOperationCode#> + dp.PackFromRgba64(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + } + <# + } + void GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode) { #> @@ -192,6 +234,9 @@ namespace SixLabors.ImageSharp.PixelFormats { <# + GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Rgba64"); + GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba32"); diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 56d6043a61..39da9f5384 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -157,5 +157,38 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Alpha8_PackFromScaledVector4_ToRgba64() + { + // arrange + Alpha8 alpha = default; + Rgba64 actual = default; + var expected = new Rgba64(0, 0, 0, 65535); + Vector4 scaled = new Alpha8(1F).ToScaledVector4(); + + // act + alpha.PackFromScaledVector4(scaled); + alpha.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Alpha8_PackFromRgba64_ToRgba64() + { + // arrange + var alpha = default(Alpha8); + var actual = default(Rgba64); + var expected = new Rgba64(0, 0, 0, 65535); + + // act + alpha.PackFromRgba64(expected); + alpha.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index f432aca8a3..79b803be81 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -189,5 +189,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Argb32_PackFromRgba64_ToRgba64() + { + // arrange + var argb = default(Argb32); + var actual = default(Rgba64); + var expected = new Rgba64(65535, 0, 65535, 0); + + // act + argb.PackFromRgba64(expected); + argb.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 33cdadb668..bac668ebd6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -22,13 +22,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(g, p.G); Assert.Equal(b, p.B); } - + [Fact] public unsafe void ByteLayoutIsSequentialBgr() { var color = new Bgr24(1, 2, 3); byte* ptr = (byte*)&color; - + Assert.Equal(3, ptr[0]); Assert.Equal(2, ptr[1]); Assert.Equal(1, ptr[2]); @@ -139,5 +139,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); } + + [Fact] + public void Bgr24_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Bgr24); + var actual = default(Rgba64); + var expected = new Rgba64(65535, 0, 65535, 65535); + + // act + input.PackFromRgba64(expected); + input.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index b1640c33de..39f2218321 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; namespace SixLabors.ImageSharp.Tests.PixelFormats -{ +{ public class Bgr565Tests { [Fact] @@ -144,5 +144,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Bgr565_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Bgr565); + var actual = default(Rgba64); + var expected = new Rgba64(65535, 0, 65535, 65535); + + // act + input.PackFromRgba64(expected); + input.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 71e04269df..701268f5db 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static readonly TheoryData ColorData = new TheoryData() { - { 1, 2, 3, 4 }, { 4, 5, 6, 7 }, { 0, 255, 42, 0 }, { 1, 2, 3, 255 } + { 1, 2, 3, 4 }, { 4, 5, 6, 7 }, { 0, 255, 42, 0 }, { 1, 2, 3, 255 } }; [Theory] @@ -146,5 +146,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); } + + [Fact] + public void Bgra32_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Bgra32); + var actual = default(Rgba64); + var expected = new Rgba64(65535, 0, 65535, 0); + + // act + input.PackFromRgba64(expected); + input.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 07667220fd..0bb3b2919c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -193,5 +193,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Bgra4444_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Bgra4444); + var actual = default(Rgba64); + var expected = new Rgba64(65535, 0, 65535, 0); + + // act + input.PackFromRgba64(expected); + input.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } } }