From 6a92b0cd442c34b220019ddda8928a9038dee7ab Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 26 Mar 2026 17:35:57 +0100 Subject: [PATCH] Implement missing Rgb96 methods --- .../Common/Helpers/ColorNumerics.cs | 11 ++ .../PixelImplementations/Rgb96.cs | 100 +++++++++++++----- .../PixelImplementations/Rgba32.cs | 13 +++ 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ColorNumerics.cs b/src/ImageSharp/Common/Helpers/ColorNumerics.cs index 1c30d857f6..7a0e6d47ab 100644 --- a/src/ImageSharp/Common/Helpers/ColorNumerics.cs +++ b/src/ImageSharp/Common/Helpers/ColorNumerics.cs @@ -12,6 +12,8 @@ namespace SixLabors.ImageSharp; /// internal static class ColorNumerics { + private const float Scale32Bit = 1f / 0xFFFFFFFF; + /// /// Vector for converting pixel to gray value as specified by /// ITU-R Recommendation BT.709. @@ -132,6 +134,15 @@ internal static class ColorNumerics // (V * 255 + 32895) >> 16 (byte)(((component * 255) + 32895) >> 16); + /// + /// Scales a value from an 32 bit to + /// an 8 bit equivalent. + /// + /// The 32 bit component value. + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte From32BitTo8Bit(uint component) => (byte)(component * Scale32Bit); + /// /// Scales a value from an 8 bit to /// an 16 bit equivalent. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs index 165f13b07e..6237d3d374 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// /// [StructLayout(LayoutKind.Sequential)] -public partial struct Rgb96 : IPixel +public partial struct Rgb96 : IPixel, IEquatable { private const float InvMax = 1.0f / uint.MaxValue; @@ -74,60 +74,106 @@ public partial struct Rgb96 : IPixel /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() => this.ToVector4(); + public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() => new( + public readonly Vector4 ToVector4() => new( this.R * InvMax, this.G * InvMax, this.B * InvMax, 1.0f); - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); + public static PixelOperations CreatePixelOperations() => new(); - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb96 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); + public static Rgb96 FromScaledVector4(Vector4 source) => FromVector4(source); - /// - public override string ToString() => FormattableString.Invariant($"Rgb96({this.R}, {this.G}, {this.B})"); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromVector4(Vector4 source) => FromVector4(source); - public static PixelOperations CreatePixelOperations() => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); - public static Rgb96 FromScaledVector4(Vector4 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); - public static Rgb96 FromVector4(Vector4 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - public static Rgb96 FromAbgr32(Abgr32 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); - public static Rgb96 FromArgb32(Argb32 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); - public static Rgb96 FromBgra5551(Bgra5551 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromL8(L8 source) + { + ushort rgb = ColorNumerics.From8BitTo16Bit(source.PackedValue); + return new Rgb96(rgb, rgb, rgb); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromL16(L16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); - public static Rgb96 FromBgr24(Bgr24 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromLa16(La16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); - public static Rgb96 FromBgra32(Bgra32 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromLa32(La32 source) => new(source.L, source.L, source.L); - public static Rgb96 FromL8(L8 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); - public static Rgb96 FromL16(L16 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); - public static Rgb96 FromLa16(La16 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B); - public static Rgb96 FromLa32(La32 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb96 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B); - public static Rgb96 FromRgb24(Rgb24 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16), + PixelColorType.RGB, + PixelAlphaRepresentation.None); - public static Rgb96 FromRgba32(Rgba32 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromRgb96(this); - public static Rgb96 FromRgb48(Rgb48 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override readonly int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); - public static Rgb96 FromRgba64(Rgba64 source) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly bool Equals(Rgb96 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); - public static PixelTypeInfo GetPixelTypeInfo() => throw new NotImplementedException(); + /// + public override readonly string ToString() => FormattableString.Invariant($"Rgb96({this.R}, {this.G}, {this.B})"); - public Rgba32 ToRgba32() => throw new NotImplementedException(); + /// + public override readonly bool Equals(object? obj) => obj is Rgb96 rgb && rgb.R == this.R && rgb.G == this.G && rgb.B == this.B; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 199754c690..34a7f67871 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -314,6 +314,19 @@ public partial struct Rgba32 : IPixel, IPackedVector A = ColorNumerics.From16BitTo8Bit(source.A) }; + /// + /// Initializes the pixel instance from an value. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgb96(Rgb96 source) + => new() + { + R = ColorNumerics.From32BitTo8Bit(source.R), + G = ColorNumerics.From32BitTo8Bit(source.G), + B = ColorNumerics.From32BitTo8Bit(source.B) + }; + /// /// Converts the value of this instance to a hexadecimal string. ///