From 96d0ae80b9b743ca8e67435e40ba7ff9c0937b75 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 20:14:05 +0200 Subject: [PATCH] Rgba32 <-> Argb32 <-> Bgra32 --- src/ImageSharp/PixelFormats/PixelConverter.cs | 76 +++++++- .../PixelFormats/PixelOperations{TPixel}.cs | 22 --- .../PixelConversion_ConvertFromRgba32.cs | 4 +- .../PixelFormats/PixelConverterTests.cs | 167 +++++++++--------- 4 files changed, 158 insertions(+), 111 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/PixelConverter.cs index 3686092cd2..8fde490fda 100644 --- a/src/ImageSharp/PixelFormats/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/PixelConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats @@ -16,32 +17,91 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal static class PixelConverter { - public static class Rgba32 + public static class FromRgba32 { /// - /// Converts a packed to . + /// Converts a packed to . /// [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { - // packedRgba = [aa bb gg rr] - // ROL(8, packedRgba): + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] return (packedRgba << 8) | (packedRgba >> 24); } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } } - public static class Argb32 + public static class FromArgb32 { /// - /// Converts a packed to . + /// Converts a packed to . /// [MethodImpl(InliningOptions.ShortMethod)] public static uint ToRgba32(uint packedArgb) { - // packedArgb = [bb gg rr aa] - // ROR(8, packedArgb): + // packedArgb = [bb gg rr aa] + // ROR(8, packedArgb) = [aa bb gg rr] return (packedArgb >> 8) | (packedArgb << 24); } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // REVERSE(packedArgb) = [aa rr gg bb] + return BinaryPrimitives.ReverseEndianness(packedArgb); + } + } + + public static class FromBgra32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedBgra) + { + // packedBgra = [aa rr gg bb] + // REVERSE(packedBgra) = [bb gg rr aa] + return BinaryPrimitives.ReverseEndianness(packedBgra); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedBgra) + { + // packedRgba = [aa rr gg bb] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 rr 00 bb] + // tmp3=ROL(16, tmp2) = [00 bb 00 rr] + // tmp1 + tmp3 = [aa bb gg rr] + uint tmp1 = packedBgra & 0xFF00FF00; + uint tmp2 = packedBgra & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 02b80de9b4..ad5aee8c7c 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -178,27 +178,5 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } - - /// - /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - protected internal static void GuardSpans( - ReadOnlySpan source, - string sourceParamName, - Span destination, - string destinationParamName, - int minLength) - { - Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); - Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 1be8347c3d..424020e2f2 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { uint s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); } } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { uint s = Unsafe.Add(ref dBase, i); - Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 83c4e34f2f..9b32f7aeee 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -4,7 +4,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.PixelFormats { - public class PixelConverterTests + public abstract class PixelConverterTests { public static readonly TheoryData RgbaData = new TheoryData @@ -23,34 +23,103 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { 67, 71, 101, 109 } }; - [Theory] - [MemberData(nameof(RgbaData))] - public void Rgba32ToArgb32(byte r, byte g, byte b, byte a) + public class FromRgba32 : PixelConverterTests { - Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromArgb32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); - // Act: - uint actualPacked = PixelConverter.Rgba32.ToArgb32(s.PackedValue); + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToRgba32(s.PackedValue); - // Assert: - uint expectedPacked = ReferenceImplementations.ToArgb32(s).PackedValue; + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; - Assert.Equal(expectedPacked, actualPacked); + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } } - [Theory] - [MemberData(nameof(RgbaData))] - public void Argb32ToRgba32(byte r, byte g, byte b, byte a) + public class FromBgra32 : PixelConverterTests { - Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); - // Act: - uint actualPacked = PixelConverter.Argb32.ToRgba32(s.PackedValue); + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToArgb32(s.PackedValue); - // Assert: - uint expectedPacked = ReferenceImplementations.ToRgba32(s).PackedValue; + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; - Assert.Equal(expectedPacked, actualPacked); + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } } @@ -85,66 +154,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats d.A = a; return d; } - - public static Argb32 ToArgb32(Rgba32 s) - { - Argb32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Argb32 ToArgb32(Bgra32 s) - { - Argb32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Rgba32 ToRgba32(Argb32 s) - { - Rgba32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Rgba32 ToRgba32(Bgra32 s) - { - Rgba32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Bgra32 ToBgra32(Rgba32 s) - { - Bgra32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Bgra32 ToBgra32(Argb32 s) - { - Bgra32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } } } } \ No newline at end of file