55using System . Drawing . Drawing2D ;
66using System . Numerics ;
77using System . Runtime . InteropServices ;
8+ using System . Runtime . Versioning ;
89using BenchmarkDotNet . Attributes ;
910using GeoJSON . Net . Feature ;
1011using Newtonsoft . Json ;
@@ -22,36 +23,45 @@ namespace SixLabors.ImageSharp.Drawing.Benchmarks.Drawing;
2223
2324public abstract class DrawPolygon
2425{
26+ private string artifactDir ;
27+
2528 private PointF [ ] [ ] points ;
2629
2730 private Image < Rgba32 > image ;
28- private bool isImageSharp ;
31+ private bool savedImageSharp ;
2932
3033 private SDPointF [ ] [ ] sdPoints ;
3134 private Bitmap sdBitmap ;
3235 private Graphics sdGraphics ;
33- private bool isSystem ;
36+ private bool savedSd ;
3437
3538 private SKPath skPath ;
3639 private SKSurface skSurface ;
37- private bool isSkia ;
40+ private bool savedSkia ;
3841
3942 private Executor executor ;
4043 private DestinationImage < TileDescriptor_8x16 > vecDst ;
41- private bool isBlaze ;
44+ private bool savedBlaze ;
4245
4346 protected abstract int Width { get ; }
4447
4548 protected abstract int Height { get ; }
4649
4750 protected abstract float Thickness { get ; }
4851
52+ protected abstract string BenchName { get ; }
53+
4954 protected virtual PointF [ ] [ ] GetPoints ( FeatureCollection features ) =>
5055 features . Features . SelectMany ( f => PolygonFactory . GetGeoJsonPoints ( f , Matrix3x2 . CreateScale ( 60 , 60 ) ) ) . ToArray ( ) ;
5156
57+ private string GetArtifactPath ( string name ) => System . IO . Path . Combine ( this . artifactDir , name ) ;
58+
5259 [ GlobalSetup ]
5360 public void Setup ( )
5461 {
62+ this . artifactDir = TestEnvironment . GetFullPath ( $ "artifacts\\ { BenchName } ") ;
63+ Directory . CreateDirectory ( this . artifactDir ) ;
64+
5565 string jsonContent = File . ReadAllText ( TestFile . GetInputFileFullPath ( TestImages . GeoJson . States ) ) ;
5666
5767 FeatureCollection featureCollection = JsonConvert . DeserializeObject < FeatureCollection > ( jsonContent ) ;
@@ -87,51 +97,16 @@ public void Setup()
8797 }
8898
8999 [ GlobalCleanup ]
90- public unsafe void Cleanup ( )
100+ public void Cleanup ( )
91101 {
92- string dir = "Images/DrawPolygon" ;
93- Directory . CreateDirectory ( dir ) ;
94-
95- if ( this . isImageSharp )
96- {
97- this . image . SaveAsPng ( System . IO . Path . Combine ( dir , "ImageSharp.png" ) ) ;
98- this . isImageSharp = false ;
99- }
100-
101- if ( this . isBlaze )
102- {
103- using var blazeImage = Image . WrapMemory < Rgba32 > (
104- this . vecDst . GetImageData ( ) ,
105- this . vecDst . GetBytesPerRow ( ) * this . vecDst . GetImageHeight ( ) ,
106- this . vecDst . GetImageWidth ( ) ,
107- this . vecDst . GetImageHeight ( ) ) ;
108-
109- blazeImage . SaveAsPng ( System . IO . Path . Combine ( dir , "Blaze.png" ) ) ;
110- this . isBlaze = false ;
111- }
112-
113- if ( this . isSystem )
114- {
115- this . sdBitmap . Save ( System . IO . Path . Combine ( dir , "SystemDrawing.png" ) ) ;
116- this . isSystem = false ;
117- }
118-
119- if ( this . isSkia )
120- {
121- using var skSnapshot = this . skSurface . Snapshot ( ) ;
122- using var skEncoded = skSnapshot . Encode ( ) ;
123- using var skFile = new FileStream ( System . IO . Path . Combine ( dir , "SkiaSharp.png" ) , FileMode . Create ) ;
124- skEncoded . SaveTo ( skFile ) ;
125- this . isSkia = false ;
126- }
127-
128102 this . image . Dispose ( ) ;
129103 this . sdGraphics . Dispose ( ) ;
130104 this . sdBitmap . Dispose ( ) ;
131105 this . skSurface . Dispose ( ) ;
132106 this . skPath . Dispose ( ) ;
133107 }
134108
109+ [ SupportedOSPlatform ( "windows" ) ]
135110 [ Benchmark ]
136111 public void SystemDrawing ( )
137112 {
@@ -142,7 +117,11 @@ public void SystemDrawing()
142117 this . sdGraphics . DrawPolygon ( pen , loop ) ;
143118 }
144119
145- this . isSystem = true ;
120+ if ( ! this . savedSd )
121+ {
122+ this . sdBitmap . Save ( this . GetArtifactPath ( "SystemDrawing.png" ) ) ;
123+ this . savedSd = true ;
124+ }
146125 }
147126
148127 [ Benchmark ]
@@ -156,7 +135,12 @@ public void ImageSharp()
156135 c . DrawPolygon ( Color . White , this . Thickness , loop ) ;
157136 }
158137 } ) ;
159- this . isImageSharp = true ;
138+
139+ if ( ! this . savedImageSharp )
140+ {
141+ this . image . SaveAsPng ( this . GetArtifactPath ( "ImageSharp.png" ) ) ;
142+ this . savedImageSharp = true ;
143+ }
160144 }
161145
162146 [ Benchmark ( Baseline = true ) ]
@@ -171,11 +155,19 @@ public void SkiaSharp()
171155 } ;
172156
173157 this . skSurface . Canvas . DrawPath ( this . skPath , paint ) ;
174- this . isSkia = true ;
158+
159+ if ( ! this . savedSkia )
160+ {
161+ using var skSnapshot = this . skSurface . Snapshot ( ) ;
162+ using var skEncoded = skSnapshot . Encode ( ) ;
163+ using var skFile = new FileStream ( this . GetArtifactPath ( "SkiaSharp.png" ) , FileMode . Create ) ;
164+ skEncoded . SaveTo ( skFile ) ;
165+ this . savedSkia = true ;
166+ }
175167 }
176168
177169 [ Benchmark ]
178- public void Blaze ( )
170+ public unsafe void Blaze ( )
179171 {
180172 VectorImageBuilder builder = new ( ) ;
181173
@@ -206,10 +198,20 @@ public void Blaze()
206198
207199 this . vecDst . DrawImage ( image , BlazeMatrix . Identity , this . executor ) ;
208200
209- this . isBlaze = true ;
201+ if ( ! this . savedBlaze )
202+ {
203+ using var blazeImage = Image . WrapMemory < Rgba32 > (
204+ this . vecDst . GetImageData ( ) ,
205+ this . vecDst . GetBytesPerRow ( ) * this . vecDst . GetImageHeight ( ) ,
206+ this . vecDst . GetImageWidth ( ) ,
207+ this . vecDst . GetImageHeight ( ) ) ;
208+
209+ blazeImage . SaveAsPng ( this . GetArtifactPath ( "Blaze.png" ) ) ;
210+ this . savedBlaze = true ;
211+ }
210212 }
211213
212- private static List < List < PointF > > GenerateOutlineList ( IPath path , float width , JointStyle jointStyle , EndCapStyle endCapStyle )
214+ public static List < List < PointF > > GenerateOutlineList ( IPath path , float width , JointStyle jointStyle , EndCapStyle endCapStyle )
213215 {
214216 List < List < PointF > > strokedLines = [ ] ;
215217
@@ -233,9 +235,19 @@ private static List<List<PointF>> GenerateOutlineList(IPath path, float width, J
233235 {
234236 foreach ( ILineSegment line in concretePath . LineSegments )
235237 {
236- ReadOnlySpan < PointF > points = line . Flatten ( ) . Span ;
237- stroker . AddLinePath ( points ) ;
238- pointCount += points . Length ;
238+ if ( line is CubicBezierLineSegment bezier )
239+ {
240+ // TODO: add bezier control points
241+ ReadOnlySpan < PointF > points = line . Flatten ( ) . Span ;
242+ stroker . AddLinePath ( points ) ;
243+ pointCount += points . Length ;
244+ }
245+ else
246+ {
247+ ReadOnlySpan < PointF > points = line . Flatten ( ) . Span ;
248+ stroker . AddLinePath ( points ) ;
249+ pointCount += points . Length ;
250+ }
239251 }
240252 }
241253 else
@@ -281,6 +293,8 @@ public class DrawPolygonAll : DrawPolygon
281293 protected override int Height => 4800 ;
282294
283295 protected override float Thickness => 2f ;
296+
297+ protected override string BenchName => nameof ( DrawPolygonAll ) ;
284298}
285299
286300public class DrawPolygonMediumThin : DrawPolygon
@@ -291,6 +305,8 @@ public class DrawPolygonMediumThin : DrawPolygon
291305
292306 protected override float Thickness => 1f ;
293307
308+ protected override string BenchName => nameof ( DrawPolygonMediumThin ) ;
309+
294310 protected override PointF [ ] [ ] GetPoints ( FeatureCollection features )
295311 {
296312 Feature state = features . Features . Single ( f => ( string ) f . Properties [ "NAME" ] == "Mississippi" ) ;
@@ -304,4 +320,6 @@ protected override PointF[][] GetPoints(FeatureCollection features)
304320public class DrawPolygonMediumThick : DrawPolygonMediumThin
305321{
306322 protected override float Thickness => 10f ;
323+
324+ protected override string BenchName => nameof ( DrawPolygonMediumThick ) ;
307325}
0 commit comments