@@ -97,7 +97,7 @@ public static ushort Get16BitBT709Luminance(float r, float g, float b)
9797 /// Scales a value from a 16 bit <see cref="ushort"/> to an
9898 /// 8 bit <see cref="byte"/> equivalent.
9999 /// </summary>
100- /// <param name="component">The 8 bit component value.</param>
100+ /// <param name="component">The 16 bit component value.</param>
101101 /// <returns>The <see cref="byte"/></returns>
102102 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
103103 public static byte From16BitTo8Bit ( ushort component ) =>
@@ -132,6 +132,49 @@ public static byte From16BitTo8Bit(ushort component) =>
132132 // (V * 255 + 32895) >> 16
133133 ( byte ) ( ( ( component * 255 ) + 32895 ) >> 16 ) ;
134134
135+ /// <summary>
136+ /// Scales a value from a 32 bit <see cref="uint"/> to an
137+ /// 8 bit <see cref="byte"/> equivalent.
138+ /// </summary>
139+ /// <param name="component">The 32 bit component value.</param>
140+ /// <returns>The <see cref="byte"/> value.</returns>
141+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
142+ public static byte From32BitTo8Bit ( uint component ) =>
143+
144+ // To scale to 8 bits from a 32-bit value V the required value is:
145+ //
146+ // (V * 255) / 4294967295
147+ //
148+ // Since:
149+ //
150+ // 4294967295 = 255 * 16843009
151+ //
152+ // this reduces exactly to:
153+ //
154+ // V / 16843009
155+ //
156+ // To round to nearest using integer arithmetic we add half the divisor
157+ // before dividing:
158+ //
159+ // (V + 16843009 / 2) / 16843009
160+ //
161+ // where:
162+ //
163+ // 16843009 / 2 = 8421504.5
164+ //
165+ // Using 8421504 ensures correct round-to-nearest behaviour:
166+ //
167+ // 8421504 -> 0
168+ // 8421505 -> 1
169+ //
170+ // The addition must be performed in 64-bit to avoid overflow for large
171+ // input values (for example uint.MaxValue).
172+ //
173+ // Final exact integer implementation:
174+ //
175+ // ((ulong)V + 8421504) / 16843009
176+ ( byte ) ( ( component + 8421504UL ) / 16843009UL ) ;
177+
135178 /// <summary>
136179 /// Scales a value from an 8 bit <see cref="byte"/> to
137180 /// an 16 bit <see cref="ushort"/> equivalent.
@@ -142,6 +185,26 @@ public static byte From16BitTo8Bit(ushort component) =>
142185 public static ushort From8BitTo16Bit ( byte component )
143186 => ( ushort ) ( component * 257 ) ;
144187
188+ /// <summary>
189+ /// Scales a value from an 16 bit <see cref="byte"/> to
190+ /// an 16 bit <see cref="uint"/> equivalent.
191+ /// </summary>
192+ /// <param name="component">The 16 bit component value.</param>
193+ /// <returns>The 32 bit <see cref="uint"/></returns>
194+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
195+ public static uint From16BitTo32Bit ( ushort component )
196+ => ( uint ) ( component * 65537 ) ;
197+
198+ /// <summary>
199+ /// Scales a value from an 8 bit <see cref="byte"/> to
200+ /// an 32 bit <see cref="ushort"/> equivalent.
201+ /// </summary>
202+ /// <param name="component">The 8 bit component value.</param>
203+ /// <returns>The 32 bit <see cref="uint"/></returns>
204+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
205+ public static uint From8BitTo32Bit ( byte component )
206+ => ( uint ) ( component * 16843009 ) ;
207+
145208 /// <summary>
146209 /// Returns how many bits are required to store the specified number of colors.
147210 /// Performs a Log2() on the value.
0 commit comments