// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.PixelFormats; /// /// Unpacked pixel type containing four 32-bit floating-point values typically ranging from 0 to 1. /// The color components are stored in red, green, blue, and alpha order. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// /// /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// [StructLayout(LayoutKind.Sequential)] public partial struct RgbaVector : IPixel { /// /// Gets or sets the red component. /// public float R; /// /// Gets or sets the green component. /// public float G; /// /// Gets or sets the blue component. /// public float B; /// /// Gets or sets the alpha component. /// public float A; private const float MaxBytes = byte.MaxValue; private static readonly Vector4 Max = new(MaxBytes); private static readonly Vector4 Half = new(0.5F); /// /// Initializes a new instance of the struct. /// /// The red component. /// The green component. /// The blue component. /// The alpha component. [MethodImpl(InliningOptions.ShortMethod)] public RgbaVector(float r, float g, float b, float a = 1) { this.R = r; this.G = g; this.B = b; this.A = a; } /// /// Compares two objects for equality. /// /// The on the left side of the operand. /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); /// /// Compares two objects for equality. /// /// The on the left side of the operand. /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); /// /// Creates a new instance of the struct. /// /// /// The hexadecimal representation of the combined color components arranged /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. /// /// /// The . /// public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( PixelComponentInfo.Create(4, 32, 32, 32, 32), PixelColorType.RGB | PixelColorType.Alpha, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); this.R = vector.X; this.G = vector.Y; this.B = vector.Z; this.A = vector.W; } /// [MethodImpl(InliningOptions.ShortMethod)] public readonly Vector4 ToVector4() => new(this.R, this.G, this.B, this.A); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Converts the value of this instance to a hexadecimal string. /// /// A hexadecimal string representation of the value. public readonly string ToHex() { // Hex is RRGGBBAA Vector4 vector = this.ToVector4() * Max; vector += Half; uint hexOrder = (uint)((byte)vector.W | ((byte)vector.Z << 8) | ((byte)vector.Y << 16) | ((byte)vector.X << 24)); return hexOrder.ToString("X8", CultureInfo.InvariantCulture); } /// public override readonly bool Equals(object? obj) => obj is RgbaVector other && this.Equals(other); /// [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(RgbaVector other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B) && this.A.Equals(other.A); /// public override readonly string ToString() => FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"); /// public override readonly int GetHashCode() => HashCode.Combine(this.R, this.G, this.B, this.A); }