44using System . Buffers ;
55using System . Numerics ;
66using System . Runtime . CompilerServices ;
7+ using System . Runtime . InteropServices ;
78using SixLabors . ImageSharp . Advanced ;
89using SixLabors . ImageSharp . Memory ;
910using SixLabors . ImageSharp . PixelFormats ;
@@ -34,17 +35,25 @@ public OilPaintingProcessor(Configuration configuration, OilPaintingProcessor de
3435 /// <inheritdoc/>
3536 protected override void OnFrameApply ( ImageFrame < TPixel > source )
3637 {
38+ int levels = Math . Clamp ( this . definition . Levels , 1 , 255 ) ;
3739 int brushSize = Math . Clamp ( this . definition . BrushSize , 1 , Math . Min ( source . Width , source . Height ) ) ;
3840
3941 using Buffer2D < TPixel > targetPixels = this . Configuration . MemoryAllocator . Allocate2D < TPixel > ( source . Size ( ) ) ;
4042
4143 source . CopyTo ( targetPixels ) ;
4244
43- RowIntervalOperation operation = new ( this . SourceRectangle , targetPixels , source . PixelBuffer , this . Configuration , brushSize >> 1 , this . definition . Levels ) ;
44- ParallelRowIterator . IterateRowIntervals (
45+ RowIntervalOperation operation = new ( this . SourceRectangle , targetPixels , source . PixelBuffer , this . Configuration , brushSize >> 1 , levels ) ;
46+ try
47+ {
48+ ParallelRowIterator . IterateRowIntervals (
4549 this . Configuration ,
4650 this . SourceRectangle ,
4751 in operation ) ;
52+ }
53+ catch ( Exception ex )
54+ {
55+ throw new ImageProcessingException ( "The OilPaintProcessor failed. The most likely reason is that a pixel component was outside of its' allowed range." , ex ) ;
56+ }
4857
4958 Buffer2D < TPixel > . SwapOrCopyContent ( source . PixelBuffer , targetPixels ) ;
5059 }
@@ -105,18 +114,18 @@ public void Invoke(in RowInterval rows)
105114 Span < Vector4 > targetRowVector4Span = targetRowBuffer . Memory . Span ;
106115 Span < Vector4 > targetRowAreaVector4Span = targetRowVector4Span . Slice ( this . bounds . X , this . bounds . Width ) ;
107116
108- ref float binsRef = ref bins . GetReference ( ) ;
109- ref int intensityBinRef = ref Unsafe . As < float , int > ( ref binsRef ) ;
110- ref float redBinRef = ref Unsafe . Add ( ref binsRef , ( uint ) this . levels ) ;
111- ref float blueBinRef = ref Unsafe . Add ( ref redBinRef , ( uint ) this . levels ) ;
112- ref float greenBinRef = ref Unsafe . Add ( ref blueBinRef , ( uint ) this . levels ) ;
117+ Span < float > binsSpan = bins . GetSpan ( ) ;
118+ Span < int > intensityBinsSpan = MemoryMarshal . Cast < float , int > ( binsSpan ) ;
119+ Span < float > redBinSpan = binsSpan [ this . levels .. ] ;
120+ Span < float > blueBinSpan = redBinSpan [ this . levels .. ] ;
121+ Span < float > greenBinSpan = blueBinSpan [ this . levels .. ] ;
113122
114123 for ( int y = rows . Min ; y < rows . Max ; y ++ )
115124 {
116125 Span < TPixel > sourceRowPixelSpan = this . source . DangerousGetRowSpan ( y ) ;
117126 Span < TPixel > sourceRowAreaPixelSpan = sourceRowPixelSpan . Slice ( this . bounds . X , this . bounds . Width ) ;
118127
119- PixelOperations < TPixel > . Instance . ToVector4 ( this . configuration , sourceRowAreaPixelSpan , sourceRowAreaVector4Span ) ;
128+ PixelOperations < TPixel > . Instance . ToVector4 ( this . configuration , sourceRowAreaPixelSpan , sourceRowAreaVector4Span , PixelConversionModifiers . Scale ) ;
120129
121130 for ( int x = this . bounds . X ; x < this . bounds . Right ; x ++ )
122131 {
@@ -140,29 +149,29 @@ public void Invoke(in RowInterval rows)
140149 int offsetX = x + fxr ;
141150 offsetX = Numerics . Clamp ( offsetX , 0 , maxX ) ;
142151
143- Vector4 vector = sourceOffsetRow [ offsetX ] . ToVector4 ( ) ;
152+ Vector4 vector = sourceOffsetRow [ offsetX ] . ToScaledVector4 ( ) ;
144153
145154 float sourceRed = vector . X ;
146155 float sourceBlue = vector . Z ;
147156 float sourceGreen = vector . Y ;
148157
149158 int currentIntensity = ( int ) MathF . Round ( ( sourceBlue + sourceGreen + sourceRed ) / 3F * ( this . levels - 1 ) ) ;
150159
151- Unsafe . Add ( ref intensityBinRef , ( uint ) currentIntensity ) ++ ;
152- Unsafe . Add ( ref redBinRef , ( uint ) currentIntensity ) + = sourceRed ;
153- Unsafe . Add ( ref blueBinRef , ( uint ) currentIntensity ) + = sourceBlue ;
154- Unsafe . Add ( ref greenBinRef , ( uint ) currentIntensity ) + = sourceGreen ;
160+ intensityBinsSpan [ currentIntensity ] ++ ;
161+ redBinSpan [ currentIntensity ] += sourceRed ;
162+ blueBinSpan [ currentIntensity ] += sourceBlue ;
163+ greenBinSpan [ currentIntensity ] += sourceGreen ;
155164
156- if ( Unsafe . Add ( ref intensityBinRef , ( uint ) currentIntensity ) > maxIntensity )
165+ if ( intensityBinsSpan [ currentIntensity ] > maxIntensity )
157166 {
158- maxIntensity = Unsafe . Add ( ref intensityBinRef , ( uint ) currentIntensity ) ;
167+ maxIntensity = intensityBinsSpan [ currentIntensity ] ;
159168 maxIndex = currentIntensity ;
160169 }
161170 }
162171
163- float red = MathF . Abs ( Unsafe . Add ( ref redBinRef , ( uint ) maxIndex ) / maxIntensity ) ;
164- float blue = MathF . Abs ( Unsafe . Add ( ref blueBinRef , ( uint ) maxIndex ) / maxIntensity ) ;
165- float green = MathF . Abs ( Unsafe . Add ( ref greenBinRef , ( uint ) maxIndex ) / maxIntensity ) ;
172+ float red = redBinSpan [ maxIndex ] / maxIntensity ;
173+ float blue = blueBinSpan [ maxIndex ] / maxIntensity ;
174+ float green = greenBinSpan [ maxIndex ] / maxIntensity ;
166175 float alpha = sourceRowVector4Span [ x ] . W ;
167176
168177 targetRowVector4Span [ x ] = new Vector4 ( red , green , blue , alpha ) ;
@@ -171,7 +180,7 @@ public void Invoke(in RowInterval rows)
171180
172181 Span < TPixel > targetRowAreaPixelSpan = this . targetPixels . DangerousGetRowSpan ( y ) . Slice ( this . bounds . X , this . bounds . Width ) ;
173182
174- PixelOperations < TPixel > . Instance . FromVector4Destructive ( this . configuration , targetRowAreaVector4Span , targetRowAreaPixelSpan ) ;
183+ PixelOperations < TPixel > . Instance . FromVector4Destructive ( this . configuration , targetRowAreaVector4Span , targetRowAreaPixelSpan , PixelConversionModifiers . Scale ) ;
175184 }
176185 }
177186 }
0 commit comments