33
44using System . Buffers ;
55using System . Numerics ;
6+ using System . Runtime . CompilerServices ;
7+ using System . Runtime . InteropServices ;
68using System . Runtime . Intrinsics ;
79using SixLabors . ImageSharp . Memory ;
810using SixLabors . ImageSharp . PixelFormats ;
@@ -14,62 +16,132 @@ namespace SixLabors.ImageSharp.Formats;
1416/// </summary>
1517internal static class EncodingUtilities
1618{
17- public static bool ShouldClearTransparentPixels < TPixel > ( TransparentColorMode mode )
19+ /// <summary>
20+ /// Determines if transparent pixels can be replaced based on the specified color mode and pixel type.
21+ /// </summary>
22+ /// <typeparam name="TPixel">The type of the pixel.</typeparam>
23+ /// <param name="mode">Indicates the color mode used to assess the ability to replace transparent pixels.</param>
24+ /// <returns>Returns true if transparent pixels can be replaced; otherwise, false.</returns>
25+ public static bool ShouldReplaceTransparentPixels < TPixel > ( TransparentColorMode mode )
26+ where TPixel : unmanaged, IPixel < TPixel >
27+ => mode == TransparentColorMode . Clear && TPixel . GetPixelTypeInfo ( ) . AlphaRepresentation == PixelAlphaRepresentation . Unassociated ;
28+
29+ /// <summary>
30+ /// Replaces pixels with a transparent alpha component with fully transparent pixels.
31+ /// </summary>
32+ /// <typeparam name="TPixel">The type of the pixel.</typeparam>
33+ /// <param name="frame">The <see cref="ImageFrame{TPixel}"/> where the transparent pixels will be changed.</param>
34+ public static void ReplaceTransparentPixels < TPixel > ( ImageFrame < TPixel > frame )
1835 where TPixel : unmanaged, IPixel < TPixel >
19- => mode == TransparentColorMode . Clear &&
20- TPixel . GetPixelTypeInfo ( ) . AlphaRepresentation == PixelAlphaRepresentation . Unassociated ;
36+ => ReplaceTransparentPixels ( frame . Configuration , frame . PixelBuffer ) ;
2137
2238 /// <summary>
23- /// Convert transparent pixels, to pixels represented by <paramref name="color"/>, which can yield
24- /// to better compression in some cases.
39+ /// Replaces pixels with a transparent alpha component with fully transparent pixels.
2540 /// </summary>
2641 /// <typeparam name="TPixel">The type of the pixel.</typeparam>
27- /// <param name="clone">The cloned <see cref="ImageFrame{TPixel}"/> where the transparent pixels will be changed.</param>
28- /// <param name="color">The color to replace transparent pixels with.</param>
29- public static void ClearTransparentPixels < TPixel > ( ImageFrame < TPixel > clone , Color color )
42+ /// <param name="configuration">The configuration.</param>
43+ /// <param name="buffer">The <see cref="Buffer2D{TPixel}"/> where the transparent pixels will be changed.</param>
44+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
45+ public static void ReplaceTransparentPixels < TPixel > ( Configuration configuration , Buffer2D < TPixel > buffer )
3046 where TPixel : unmanaged, IPixel < TPixel >
3147 {
32- Buffer2DRegion < TPixel > buffer = clone . PixelBuffer . GetRegion ( ) ;
33- ClearTransparentPixels ( clone . Configuration , ref buffer , color ) ;
48+ Buffer2DRegion < TPixel > region = buffer . GetRegion ( ) ;
49+ ReplaceTransparentPixels ( configuration , in region ) ;
3450 }
3551
3652 /// <summary>
37- /// Convert transparent pixels, to pixels represented by <paramref name="color"/>, which can yield
38- /// to better compression in some cases.
53+ /// Replaces pixels with a transparent alpha component with fully transparent pixels.
3954 /// </summary>
4055 /// <typeparam name="TPixel">The type of the pixel.</typeparam>
4156 /// <param name="configuration">The configuration.</param>
42- /// <param name="clone">The cloned <see cref="Buffer2DRegion{T}"/> where the transparent pixels will be changed.</param>
43- /// <param name="color">The color to replace transparent pixels with.</param>
44- public static void ClearTransparentPixels < TPixel > (
57+ /// <param name="region">The <see cref="Buffer2DRegion{T}"/> where the transparent pixels will be changed.</param>
58+ public static void ReplaceTransparentPixels < TPixel > (
4559 Configuration configuration ,
46- ref Buffer2DRegion < TPixel > clone ,
47- Color color )
60+ in Buffer2DRegion < TPixel > region )
4861 where TPixel : unmanaged, IPixel < TPixel >
4962 {
50- using IMemoryOwner < Vector4 > vectors = configuration . MemoryAllocator . Allocate < Vector4 > ( clone . Width ) ;
63+ using IMemoryOwner < Vector4 > vectors = configuration . MemoryAllocator . Allocate < Vector4 > ( region . Width ) ;
5164 Span < Vector4 > vectorsSpan = vectors . GetSpan ( ) ;
52- Vector4 replacement = color . ToScaledVector4 ( ) ;
53- for ( int y = 0 ; y < clone . Height ; y ++ )
65+ for ( int y = 0 ; y < region . Height ; y ++ )
5466 {
55- Span < TPixel > span = clone . DangerousGetRowSpan ( y ) ;
67+ Span < TPixel > span = region . DangerousGetRowSpan ( y ) ;
5668 PixelOperations < TPixel > . Instance . ToVector4 ( configuration , span , vectorsSpan , PixelConversionModifiers . Scale ) ;
57- ClearTransparentPixelRow ( vectorsSpan , replacement ) ;
69+ ReplaceTransparentPixels ( vectorsSpan ) ;
5870 PixelOperations < TPixel > . Instance . FromVector4Destructive ( configuration , vectorsSpan , span , PixelConversionModifiers . Scale ) ;
5971 }
6072 }
6173
62- private static void ClearTransparentPixelRow (
63- Span < Vector4 > vectorsSpan ,
64- Vector4 replacement )
74+ /// <summary>
75+ /// Replaces pixels with a transparent alpha component with fully transparent pixels.
76+ /// </summary>
77+ /// <param name="source">A span of color vectors that will be checked for transparency and potentially modified.</param>
78+ public static void ReplaceTransparentPixels ( Span < Vector4 > source )
6579 {
66- if ( Vector128 . IsHardwareAccelerated )
80+ if ( Vector512 . IsHardwareAccelerated && source . Length >= 4 )
81+ {
82+ Span < Vector512 < float > > source512 = MemoryMarshal . Cast < Vector4 , Vector512 < float > > ( source ) ;
83+ for ( int i = 0 ; i < source512 . Length ; i ++ )
84+ {
85+ ref Vector512 < float > v = ref source512 [ i ] ;
86+
87+ // Do `vector < threshold`
88+ Vector512 < float > mask = Vector512 . Equals ( v , Vector512 < float > . Zero ) ;
89+
90+ // Replicate the result for W to all elements (is AllBitsSet if the W was 0 and Zero otherwise)
91+ mask = Vector512 . Shuffle ( mask , Vector512 . Create ( 3 , 3 , 3 , 3 , 7 , 7 , 7 , 7 , 11 , 11 , 11 , 11 , 15 , 15 , 15 , 15 ) ) ;
92+
93+ // Use the mask to select the replacement vector
94+ // (replacement & mask) | (v512 & ~mask)
95+ v = Vector512 . ConditionalSelect ( mask , Vector512 < float > . Zero , v ) ;
96+ }
97+
98+ int m = Numerics . Modulo4 ( source . Length ) ;
99+ if ( m != 0 )
100+ {
101+ for ( int i = source . Length - m ; i < source . Length ; i ++ )
102+ {
103+ if ( source [ i ] . W == 0 )
104+ {
105+ source [ i ] = Vector4 . Zero ;
106+ }
107+ }
108+ }
109+ }
110+ else if ( Vector256 . IsHardwareAccelerated && source . Length >= 2 )
67111 {
68- Vector128 < float > replacement128 = replacement . AsVector128 ( ) ;
112+ Span < Vector256 < float > > source256 = MemoryMarshal . Cast < Vector4 , Vector256 < float > > ( source ) ;
113+ for ( int i = 0 ; i < source256 . Length ; i ++ )
114+ {
115+ ref Vector256 < float > v = ref source256 [ i ] ;
116+
117+ // Do `vector < threshold`
118+ Vector256 < float > mask = Vector256 . Equals ( v , Vector256 < float > . Zero ) ;
119+
120+ // Replicate the result for W to all elements (is AllBitsSet if the W was 0 and Zero otherwise)
121+ mask = Vector256 . Shuffle ( mask , Vector256 . Create ( 3 , 3 , 3 , 3 , 7 , 7 , 7 , 7 ) ) ;
69122
70- for ( int i = 0 ; i < vectorsSpan . Length ; i ++ )
123+ // Use the mask to select the replacement vector
124+ // (replacement & mask) | (v256 & ~mask)
125+ v = Vector256 . ConditionalSelect ( mask , Vector256 < float > . Zero , v ) ;
126+ }
127+
128+ int m = Numerics . Modulo2 ( source . Length ) ;
129+ if ( m != 0 )
130+ {
131+ for ( int i = source . Length - m ; i < source . Length ; i ++ )
132+ {
133+ if ( source [ i ] . W == 0 )
134+ {
135+ source [ i ] = Vector4 . Zero ;
136+ }
137+ }
138+ }
139+ }
140+ else if ( Vector128 . IsHardwareAccelerated )
141+ {
142+ for ( int i = 0 ; i < source . Length ; i ++ )
71143 {
72- ref Vector4 v = ref vectorsSpan [ i ] ;
144+ ref Vector4 v = ref source [ i ] ;
73145 Vector128 < float > v128 = v . AsVector128 ( ) ;
74146
75147 // Do `vector == 0`
@@ -80,16 +152,16 @@ private static void ClearTransparentPixelRow(
80152
81153 // Use the mask to select the replacement vector
82154 // (replacement & mask) | (v128 & ~mask)
83- v = Vector128 . ConditionalSelect ( mask , replacement128 , v128 ) . AsVector4 ( ) ;
155+ v = Vector128 . ConditionalSelect ( mask , Vector128 < float > . Zero , v128 ) . AsVector4 ( ) ;
84156 }
85157 }
86158 else
87159 {
88- for ( int i = 0 ; i < vectorsSpan . Length ; i ++ )
160+ for ( int i = 0 ; i < source . Length ; i ++ )
89161 {
90- if ( vectorsSpan [ i ] . W == 0F )
162+ if ( source [ i ] . W == 0F )
91163 {
92- vectorsSpan [ i ] = replacement ;
164+ source [ i ] = Vector4 . Zero ;
93165 }
94166 }
95167 }
0 commit comments