From 6dcd771c8c6d4e5140f247205eb8ff84541d9c9f Mon Sep 17 00:00:00 2001 From: dirk Date: Fri, 21 Oct 2016 17:18:27 +0200 Subject: [PATCH] Refactored color to store the value as RGBA. Former-commit-id: 67fe6a6b6cbc6ad7de60d1a86de5e7d9de1e095a Former-commit-id: 5432d1f65ec5109894a0a493063039aea539d41d Former-commit-id: 7ac0932ca72ef00618a62eadfcd132a2a3c24a86 --- src/ImageProcessorCore/Colors/Color.cs | 115 ++++++++---------- .../Colors/ColorTests.cs | 10 +- 2 files changed, 54 insertions(+), 71 deletions(-) diff --git a/src/ImageProcessorCore/Colors/Color.cs b/src/ImageProcessorCore/Colors/Color.cs index 80ee03e99..e82a1e3a8 100644 --- a/src/ImageProcessorCore/Colors/Color.cs +++ b/src/ImageProcessorCore/Colors/Color.cs @@ -6,6 +6,7 @@ namespace ImageProcessorCore { using System; + using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; @@ -46,12 +47,11 @@ namespace ImageProcessorCore { get { - return (byte)this.packedValue; + return (byte)(this.packedValue >> 24); } set { - // AABBGGRR - this.packedValue = (uint)(this.packedValue & -0x100 | value); + this.packedValue = this.packedValue & 0x00FFFFFF | (uint)value << 24; } } @@ -63,12 +63,11 @@ namespace ImageProcessorCore { get { - return (byte)(this.packedValue >> 8); + return (byte)(this.packedValue >> 16); } set { - // AABBGGRR - this.packedValue = (uint)(this.packedValue & -0xFF01 | (uint)value << 8); + this.packedValue = this.packedValue & 0xFF00FFFF | (uint)value << 16; } } @@ -79,12 +78,11 @@ namespace ImageProcessorCore { get { - return (byte)(this.packedValue >> 16); + return (byte)(this.packedValue >> 8); } set { - // AABBGGRR - this.packedValue = (uint)(this.packedValue & -0xFF0001 | (uint)(value << 16)); + this.packedValue = this.packedValue & 0xFFFF00FF | (uint)value << 8; } } @@ -95,12 +93,11 @@ namespace ImageProcessorCore { get { - return (byte)(this.packedValue >> 24); + return (byte)this.packedValue; } set { - // AABBGGRR - this.packedValue = this.packedValue & 0xFFFFFF | (uint)value << 24; + this.packedValue = this.packedValue & 0xFFFFFF00 | value; } } @@ -110,16 +107,15 @@ namespace ImageProcessorCore public uint PackedValue { get { return this.packedValue; } set { this.packedValue = value; } } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The red component. /// The green component. /// The blue component. /// The alpha component. public Color(byte r, byte g, byte b, byte a = 255) - : this() { - this.packedValue = (uint)(r | g << 8 | b << 16 | a << 24); + this.packedValue = (uint)(r << 24 | g << 16 | b << 8 | a); } /// @@ -127,46 +123,17 @@ namespace ImageProcessorCore /// /// /// The hexadecimal representation of the combined color components arranged - /// in rgb, rrggbb, or aarrggbb format to match web syntax. + /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. /// public Color(string hex) - : this() { - // Hexadecimal representations are layed out AARRGGBB to we need to do some reordering. - hex = hex.StartsWith("#") ? hex.Substring(1) : hex; + Guard.NotNullOrEmpty(hex, nameof(hex)); - if (hex.Length != 8 && hex.Length != 6 && hex.Length != 3) - { - throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); - } + hex = ToRgbaHex(hex); - if (hex.Length == 8) - { - this.packedValue = - (uint)(Convert.ToByte(hex.Substring(2, 2), 16) - | Convert.ToByte(hex.Substring(4, 2), 16) << 8 - | Convert.ToByte(hex.Substring(6, 2), 16) << 16 - | Convert.ToByte(hex.Substring(0, 2), 16) << 24); - } - else if (hex.Length == 6) + if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out this.packedValue)) { - this.packedValue = - (uint)(Convert.ToByte(hex.Substring(0, 2), 16) - | Convert.ToByte(hex.Substring(2, 2), 16) << 8 - | Convert.ToByte(hex.Substring(4, 2), 16) << 16 - | 255 << 24); - } - else - { - string rh = char.ToString(hex[0]); - string gh = char.ToString(hex[1]); - string bh = char.ToString(hex[2]); - - this.packedValue = - (uint)(Convert.ToByte(rh + rh, 16) - | Convert.ToByte(gh + gh, 16) << 8 - | Convert.ToByte(bh + bh, 16) << 16 - | 255 << 24); + throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); } } @@ -178,7 +145,6 @@ namespace ImageProcessorCore /// The blue component. /// The alpha component. public Color(float r, float g, float b, float a = 1) - : this() { this.packedValue = Pack(r, g, b, a); } @@ -190,7 +156,6 @@ namespace ImageProcessorCore /// The vector containing the components for the packed vector. /// public Color(Vector3 vector) - : this() { this.packedValue = Pack(ref vector); } @@ -202,7 +167,6 @@ namespace ImageProcessorCore /// The vector containing the components for the packed vector. /// public Color(Vector4 vector) - : this() { this.packedValue = Pack(ref vector); } @@ -217,7 +181,7 @@ namespace ImageProcessorCore /// The on the right side of the operand. /// /// - /// True if the current left is equal to the parameter; otherwise, false. + /// True if the parameter is equal to the parameter; otherwise, false. /// public static bool operator ==(Color left, Color right) { @@ -230,7 +194,7 @@ namespace ImageProcessorCore /// The on the left side of the operand. /// The on the right side of the operand. /// - /// True if the current left is equal to the parameter; otherwise, false. + /// True if the parameter is equal to the parameter; otherwise, false. /// public static bool operator !=(Color left, Color right) { @@ -273,7 +237,7 @@ namespace ImageProcessorCore /// public override int GetHashCode() { - return this.GetHashCode(this); + return this.packedValue.GetHashCode(); } /// @@ -307,25 +271,42 @@ namespace ImageProcessorCore [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(float x, float y, float z, float w) { - return (uint)((byte)Math.Round(x.Clamp(Zero, One) * MaxBytes) - | ((byte)Math.Round(y.Clamp(Zero, One) * MaxBytes) << 8) - | (byte)Math.Round(z.Clamp(Zero, One) * MaxBytes) << 16 - | (byte)Math.Round(w.Clamp(Zero, One) * MaxBytes) << 24); + return (uint)((byte)Math.Round(x.Clamp(Zero, One) * MaxBytes) << 24 + | (byte)Math.Round(y.Clamp(Zero, One) * MaxBytes) << 16 + | (byte)Math.Round(z.Clamp(Zero, One) * MaxBytes) << 8 + | (byte)Math.Round(w.Clamp(Zero, One) * MaxBytes)); } /// - /// Returns the hash code for this instance. + /// Converts the specified hex value to an rrggbbaa hex value. /// - /// - /// The instance of to return the hash code for. - /// + /// The hex value to convert. /// - /// A 32-bit signed integer that is the hash code for this instance. + /// A rrggbbaa hex value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetHashCode(Color packed) + private static string ToRgbaHex(string hex) { - return packed.packedValue.GetHashCode(); + hex = hex.StartsWith("#") ? hex.Substring(1) : hex; + + if (hex.Length == 8) + { + return hex; + } + else if (hex.Length == 6) + { + return hex + "FF"; + } + else if (hex.Length < 3 || hex.Length > 4) + { + return null; + } + + string red = char.ToString(hex[0]); + string green = char.ToString(hex[1]); + string blue = char.ToString(hex[2]); + string alpha = hex.Length == 3 ? "F" : char.ToString(hex[3]); + + return red + red + green + green + blue + blue + alpha + alpha; } } } \ No newline at end of file diff --git a/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs b/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs index 82e1bd80e..a2f53694e 100644 --- a/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs +++ b/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs @@ -24,13 +24,15 @@ namespace ImageProcessorCore.Tests Color color1 = new Color(0, 0, 0); Color color2 = new Color(0, 0, 0, 1F); Color color3 = new Color("#000"); - Color color4 = new Color("#000000"); - Color color5 = new Color("#FF000000"); + Color color4 = new Color("#000F"); + Color color5 = new Color("#000000"); + Color color6 = new Color("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); Assert.Equal(color1, color4); Assert.Equal(color1, color5); + Assert.Equal(color1, color6); } /// @@ -94,9 +96,9 @@ namespace ImageProcessorCore.Tests [Fact] public void ConvertHex() { - const string First = "FF000000"; + const string First = "000000FF"; Color color = Color.Black; - string second = color.PackedValue.ToString("X"); + string second = color.PackedValue.ToString("X8"); Assert.Equal(First, second); } }