diff --git a/src/ImageSharp/Colors/Color.cs b/src/ImageSharp/Colors/Color.cs index fb2ce38ac..fa83429df 100644 --- a/src/ImageSharp/Colors/Color.cs +++ b/src/ImageSharp/Colors/Color.cs @@ -10,7 +10,7 @@ namespace ImageSharp using System.Runtime.InteropServices; /// - /// Unpacked pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255. + /// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255. /// The color components are stored in red, green, blue, and alpha order. /// /// @@ -18,7 +18,7 @@ namespace ImageSharp /// as it avoids the need to create new values for modification operations. /// [StructLayout(LayoutKind.Explicit)] - public partial struct Color : IPixel + public partial struct Color : IPixel, IPackedVector { /// /// Gets or sets the red component. @@ -44,6 +44,12 @@ namespace ImageSharp [FieldOffset(3)] public byte A; + /// + /// The packed representation of the value. + /// + [FieldOffset(0)] + public uint Rgba; + /// /// The shift count for the red component /// @@ -81,6 +87,7 @@ namespace ImageSharp /// The green component. /// The blue component. /// The alpha component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Color(byte r, byte g, byte b, byte a = 255) : this() { @@ -97,10 +104,11 @@ namespace ImageSharp /// The green component. /// The blue component. /// The alpha component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Color(float r, float g, float b, float a = 1) : this() { - this = Pack(r, g, b, a); + this.Pack(r, g, b, a); } /// @@ -109,10 +117,11 @@ namespace ImageSharp /// /// The vector containing the components for the packed vector. /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Color(Vector3 vector) : this() { - this = Pack(ref vector); + this.Pack(ref vector); } /// @@ -121,12 +130,29 @@ namespace ImageSharp /// /// The vector containing the components for the packed vector. /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Color(Vector4 vector) : this() { - this = Pack(ref vector); + this = PackNew(ref vector); + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The packed value. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Color(uint packed) + : this() + { + this.Rgba = packed; } + /// + public uint PackedValue { get => this.Rgba; set => this.Rgba = value; } + /// /// Compares two objects for equality. /// @@ -142,10 +168,7 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Color left, Color right) { - return left.R == right.R - && left.G == right.G - && left.B == right.B - && left.A == right.A; + return left.Rgba == right.Rgba; } /// @@ -159,10 +182,7 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Color left, Color right) { - return left.R != right.R - && left.G != right.G - && left.B != right.B - && left.A != right.A; + return left.Rgba != right.Rgba; } /// @@ -245,7 +265,7 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) { - this = Pack(ref vector); + this.Pack(ref vector); } /// @@ -265,10 +285,7 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Color other) { - return this.R == other.R - && this.G == other.G - && this.B == other.B - && this.A == other.A; + return this.Rgba == other.Rgba; } /// @@ -308,12 +325,12 @@ namespace ImageSharp } /// - /// Packs a into a uint. + /// Packs a into a color returning a new instance as a result. /// /// The vector containing the values to pack. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Color Pack(ref Vector4 vector) + private static Color PackNew(ref Vector4 vector) { vector *= MaxBytes; vector += Half; @@ -322,31 +339,46 @@ namespace ImageSharp return new Color((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W); } + /// + /// Packs the four floats into a color. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Pack(float x, float y, float z, float w) + { + Vector4 value = new Vector4(x, y, z, w); + this.Pack(ref value); + } + /// /// Packs a into a uint. /// /// The vector containing the values to pack. - /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Color Pack(ref Vector3 vector) + private void Pack(ref Vector3 vector) { Vector4 value = new Vector4(vector, 1); - return Pack(ref value); + this.Pack(ref value); } /// - /// Packs the four floats into a . + /// Packs a into a color. /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The + /// The vector containing the values to pack. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Color Pack(float x, float y, float z, float w) + private void Pack(ref Vector4 vector) { - Vector4 value = new Vector4(x, y, z, w); - return Pack(ref value); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + + this.R = (byte)vector.X; + this.G = (byte)vector.Y; + this.B = (byte)vector.Z; + this.A = (byte)vector.W; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index c9312eed1..c40abd934 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -193,7 +193,7 @@ namespace ImageSharp.Tests int pixelCount = left * top; uint stepsPerPixel = (uint)(uint.MaxValue / pixelCount); TColor c = default(TColor); - Rgba32 t = new Rgba32(0); + Color t = new Color(0); for (int x = left; x < right; x++) for (int y = top; y < bottom; y++)