diff --git a/src/ImageSharp/Common/Helpers/ColorNumerics.cs b/src/ImageSharp/Common/Helpers/ColorNumerics.cs index 7a0e6d47ab..735f6bc597 100644 --- a/src/ImageSharp/Common/Helpers/ColorNumerics.cs +++ b/src/ImageSharp/Common/Helpers/ColorNumerics.cs @@ -12,8 +12,6 @@ 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. @@ -141,7 +139,7 @@ internal static class ColorNumerics /// The 32 bit component value. /// The value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte From32BitTo8Bit(uint component) => (byte)(component * Scale32Bit); + public static byte From32BitTo8Bit(uint component) => (byte)(component >> 24); /// /// Scales a value from an 8 bit to @@ -153,6 +151,26 @@ internal static class ColorNumerics public static ushort From8BitTo16Bit(byte component) => (ushort)(component * 257); + /// + /// Scales a value from an 16 bit to + /// an 16 bit equivalent. + /// + /// The 16 bit component value. + /// The 32 bit + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint From16BitTo32Bit(ushort component) + => (uint)(component * 65537); + + /// + /// Scales a value from an 8 bit to + /// an 32 bit equivalent. + /// + /// The 8 bit component value. + /// The 32 bit + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint From8BitTo32Bit(byte component) + => (uint)(component * 16843009); + /// /// Returns how many bits are required to store the specified number of colors. /// Performs a Log2() on the value. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs index d318b067c1..5f61d5778b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb96.cs @@ -19,7 +19,7 @@ public partial struct Rgb96 : IPixel, IEquatable { private const float InvMax = 1.0f / uint.MaxValue; - private const double Max = uint.MaxValue; + private const float Max = uint.MaxValue; /// /// Gets the red component. @@ -94,15 +94,19 @@ public partial struct Rgb96 : IPixel, IEquatable /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromVector4(Vector4 source) => FromVector4(source); + public static Rgb96 FromVector4(Vector4 source) + { + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One) * Max; + return new Rgb96((uint)MathF.Round(source.X), (uint)MathF.Round(source.Y), (uint)MathF.Round(source.Z)); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); + public static Rgb96 FromAbgr32(Abgr32 source) => new(ColorNumerics.From8BitTo32Bit(source.R), ColorNumerics.From8BitTo32Bit(source.G), ColorNumerics.From8BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); + public static Rgb96 FromArgb32(Argb32 source) => new(ColorNumerics.From8BitTo32Bit(source.R), ColorNumerics.From8BitTo32Bit(source.G), ColorNumerics.From8BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -110,47 +114,59 @@ public partial struct Rgb96 : IPixel, IEquatable /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); + public static Rgb96 FromBgr24(Bgr24 source) => new(ColorNumerics.From8BitTo32Bit(source.R), ColorNumerics.From8BitTo32Bit(source.G), ColorNumerics.From8BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); + public static Rgb96 FromBgra32(Bgra32 source) => new(ColorNumerics.From8BitTo32Bit(source.R), ColorNumerics.From8BitTo32Bit(source.G), ColorNumerics.From8BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgb96 FromL8(L8 source) { - ushort rgb = ColorNumerics.From8BitTo16Bit(source.PackedValue); + uint rgb = ColorNumerics.From8BitTo32Bit(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 FromL16(L16 source) + { + uint rgb = ColorNumerics.From16BitTo32Bit(source.PackedValue); + return new(rgb, rgb, rgb); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromLa16(La16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); + public static Rgb96 FromLa16(La16 source) + { + uint rgb = ColorNumerics.From8BitTo32Bit((byte)source.PackedValue); + return new(rgb, rgb, rgb); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromLa32(La32 source) => new(source.L, source.L, source.L); + public static Rgb96 FromLa32(La32 source) + { + uint rgb = ColorNumerics.From16BitTo32Bit(source.L); + return new(rgb, rgb, rgb); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); + public static Rgb96 FromRgb24(Rgb24 source) => new(ColorNumerics.From8BitTo32Bit(source.R), ColorNumerics.From8BitTo32Bit(source.G), ColorNumerics.From8BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); + public static Rgb96 FromRgba32(Rgba32 source) => new(ColorNumerics.From8BitTo32Bit(source.R), ColorNumerics.From8BitTo32Bit(source.G), ColorNumerics.From8BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B); + public static Rgb96 FromRgb48(Rgb48 source) => new(ColorNumerics.From16BitTo32Bit(source.R), ColorNumerics.From16BitTo32Bit(source.G), ColorNumerics.From16BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb96 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B); + public static Rgb96 FromRgba64(Rgba64 source) => new(ColorNumerics.From16BitTo32Bit(source.R), ColorNumerics.From16BitTo32Bit(source.G), ColorNumerics.From16BitTo32Bit(source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 4913724473..72215dec00 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -325,7 +325,8 @@ public partial struct Rgba32 : IPixel, IPackedVector { R = ColorNumerics.From32BitTo8Bit(source.R), G = ColorNumerics.From32BitTo8Bit(source.G), - B = ColorNumerics.From32BitTo8Bit(source.B) + B = ColorNumerics.From32BitTo8Bit(source.B), + A = byte.MaxValue }; ///