77// </summary>
88// --------------------------------------------------------------------------------------------------------------------
99
10+ #nullable enable
11+
1012namespace OxyPlot . ImageSharp
1113{
1214 using System ;
@@ -158,7 +160,7 @@ public void SaveAsJpeg(Stream output, int quality = 75)
158160 }
159161
160162 /// <inheritdoc/>
161- public override void DrawText ( ScreenPoint p , string text , OxyColor fill , string fontFamily = null , double fontSize = 10 , double fontWeight = 400 , double rotation = 0 , OxyPlot . HorizontalAlignment horizontalAlignment = OxyPlot . HorizontalAlignment . Left , OxyPlot . VerticalAlignment verticalAlignment = OxyPlot . VerticalAlignment . Top , OxySize ? maxSize = null )
163+ public override void DrawText ( ScreenPoint p , string text , OxyColor fill , string ? fontFamily = null , double fontSize = 10 , double fontWeight = 400 , double rotation = 0 , OxyPlot . HorizontalAlignment horizontalAlignment = OxyPlot . HorizontalAlignment . Left , OxyPlot . VerticalAlignment verticalAlignment = OxyPlot . VerticalAlignment . Top , OxySize ? maxSize = null )
162164 {
163165 if ( text == null || ! fill . IsVisible ( ) )
164166 {
@@ -176,18 +178,18 @@ public override void DrawText(ScreenPoint p, string text, OxyColor fill, string
176178 var sin = ( float ) Math . Sin ( rotation * Math . PI / 180.0 ) ;
177179
178180 // measure bounds of the whole text (we only need the height)
179- var bounds = this . MeasureTextLoose ( text , fontFamily , fontSize , fontWeight ) ;
181+ var bounds = this . MeasureTextLoose ( text , fontFamily ! , fontSize , fontWeight ) ;
180182 var boundsHeight = this . Convert ( bounds . Height ) ;
181183 var offsetHeight = new PointF ( boundsHeight * - sin , boundsHeight * cos ) ;
182184
183185 // determine the font metrids for this font size at 96 DPI
184- var actualDescent = this . Convert ( actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . Descender ) ) ;
186+ var actualDescent = this . Convert ( actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . VerticalMetrics . Descender ) ) ;
185187 var offsetDescent = new PointF ( actualDescent * - sin , actualDescent * cos ) ;
186188
187- var actualLineHeight = this . Convert ( actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . LineHeight ) ) ;
189+ var actualLineHeight = this . Convert ( actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . VerticalMetrics . LineHeight ) ) ;
188190 var offsetLineHeight = new PointF ( actualLineHeight * - sin , actualLineHeight * cos ) ;
189191
190- var actualLineGap = this . Convert ( actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . LineGap ) ) ;
192+ var actualLineGap = this . Convert ( actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . VerticalMetrics . LineGap ) ) ;
191193 var offsetLineGap = new PointF ( actualLineGap * - sin , actualLineGap * cos ) ;
192194
193195 // find top of the whole text
@@ -222,7 +224,7 @@ public override void DrawText(ScreenPoint p, string text, OxyColor fill, string
222224 }
223225
224226 // measure bounds of just the line (we only need the width)
225- var lineBounds = this . MeasureTextLoose ( line , fontFamily , fontSize , fontWeight ) ;
227+ var lineBounds = this . MeasureTextLoose ( line , fontFamily ! , fontSize , fontWeight ) ;
226228 var lineBoundsWidth = this . Convert ( lineBounds . Width ) ;
227229 var offsetLineWidth = new PointF ( lineBoundsWidth * cos , lineBoundsWidth * sin ) ;
228230
@@ -254,9 +256,9 @@ public override void DrawText(ScreenPoint p, string text, OxyColor fill, string
254256 }
255257
256258 /// <inheritdoc/>
257- public override OxySize MeasureText ( string text , string fontFamily = null , double fontSize = 10 , double fontWeight = 500 )
259+ public override OxySize MeasureText ( string text , string ? fontFamily = null , double fontSize = 10 , double fontWeight = 500 )
258260 {
259- return this . MeasureTextLoose ( text , fontFamily , fontSize , fontWeight ) ;
261+ return this . MeasureTextLoose ( text , fontFamily ! , fontSize , fontWeight ) ;
260262 }
261263
262264 /// <inheritdoc/>
@@ -367,53 +369,70 @@ public override void DrawImage(
367369 /// <inheritdoc/>
368370 public override void DrawLine ( IList < ScreenPoint > points , OxyColor stroke , double thickness , EdgeRenderingMode edgeRenderingMode , double [ ] dashArray , LineJoin lineJoin )
369371 {
370- if ( points . Count < 2 || ! stroke . IsVisible ( ) || thickness <= 0 )
372+ if ( points . Count < 2 )
371373 {
372374 return ;
373375 }
374376
375- var actualThickness = this . GetActualThickness ( thickness , edgeRenderingMode ) ;
376- var actualDashArray = dashArray != null
377- ? this . ConvertDashArray ( dashArray , actualThickness )
378- : null ;
377+ var pen = this . GetPen ( stroke , thickness , dashArray , edgeRenderingMode , lineJoin ) ;
378+
379+ if ( pen is null )
380+ {
381+ return ;
382+ }
379383
380- var pen = actualDashArray != null
381- ? new Pen ( ToRgba32 ( stroke ) , actualThickness , actualDashArray )
382- : new Pen ( ToRgba32 ( stroke ) , actualThickness ) ;
383384 var actualPoints = this . GetActualPoints ( points , thickness , edgeRenderingMode ) . ToArray ( ) ;
384385 var options = this . CreateDrawingOptions ( this . ShouldUseAntiAliasingForLine ( edgeRenderingMode , points ) ) ;
385386
387+ if ( this . PointsAreAllTheSame ( actualPoints ) )
388+ {
389+ // return early if all the points are the same, as this causes a crash in ImageSharp
390+ return ;
391+ }
392+
386393 this . Target . Mutate ( img =>
387394 {
388- img . DrawLines ( options , pen , actualPoints ) ;
395+ img . DrawLine ( options , pen , actualPoints ) ;
389396 } ) ;
390397 }
391398
399+ /// <summary>
400+ /// Determines whether all the points in the given collection are the same.
401+ /// </summary>
402+ /// <param name="points">The collection of points to compare.</param>
403+ /// <returns><code>true</code> if all the points compare equal, otherwise <code>false</code>.</returns>
404+ private bool PointsAreAllTheSame ( IList < PointF > points )
405+ {
406+ for ( int i = 1 ; i < points . Count ; i ++ )
407+ {
408+ if ( points [ i ] != points [ 0 ] )
409+ {
410+ return false ;
411+ }
412+ }
413+
414+ return true ;
415+ }
416+
392417 /// <inheritdoc/>
393- public override void DrawPolygon ( IList < ScreenPoint > points , OxyColor fill , OxyColor stroke , double thickness , EdgeRenderingMode edgeRenderingMode , double [ ] dashArray , LineJoin lineJoin )
418+ public override void DrawPolygon ( IList < ScreenPoint > points , OxyColor fill , OxyColor stroke , double thickness , EdgeRenderingMode edgeRenderingMode , double [ ] ? dashArray , LineJoin lineJoin )
394419 {
395- var fillInvisible = ! fill . IsVisible ( ) ;
396- var strokeInvisible = ! stroke . IsVisible ( ) || thickness <= 0 ;
420+ if ( points . Count < 2 )
421+ {
422+ return ;
423+ }
424+
425+ var pen = this . GetPen ( stroke , thickness , dashArray , edgeRenderingMode , lineJoin ) ;
426+ var brush = this . GetBrush ( fill ) ;
397427
398- if ( ( fillInvisible && strokeInvisible ) || points . Count < 2 )
428+ if ( pen is null && brush is null )
399429 {
400430 return ;
401431 }
402432
403- var actualThickness = this . GetActualThickness ( thickness , edgeRenderingMode ) ;
404- var actualDashArray = dashArray != null
405- ? this . ConvertDashArray ( dashArray , actualThickness )
406- : null ;
407-
408- var pen = strokeInvisible ? null :
409- actualDashArray != null
410- ? new Pen ( ToRgba32 ( stroke ) , actualThickness , actualDashArray )
411- : new Pen ( ToRgba32 ( stroke ) , actualThickness ) ;
412433 var actualPoints = this . GetActualPoints ( points , thickness , edgeRenderingMode ) . ToArray ( ) ;
413434 var options = this . CreateDrawingOptions ( this . ShouldUseAntiAliasingForLine ( edgeRenderingMode , points ) ) ;
414435
415- var brush = fillInvisible ? null : Brushes . Solid ( ToRgba32 ( fill ) ) ;
416-
417436 this . Target . Mutate ( img =>
418437 {
419438 if ( brush != null )
@@ -428,6 +447,83 @@ public override void DrawPolygon(IList<ScreenPoint> points, OxyColor fill, OxyCo
428447 } ) ;
429448 }
430449
450+ /// <summary>
451+ /// Gets a <see cref="Brush"/>.
452+ /// </summary>
453+ /// <param name="fill">The fill color.</param>
454+ /// <returns>A <see cref="Brush"/>, or <code>null</code> if the fill would be invisible.</returns>
455+ private Brush ? GetBrush ( OxyColor fill )
456+ {
457+ if ( ! fill . IsVisible ( ) )
458+ {
459+ return null ;
460+ }
461+
462+ return Brushes . Solid ( ToRgba32 ( fill ) ) ;
463+ }
464+
465+ /// <summary>
466+ /// Gets a <see cref="Pen"/>.
467+ /// </summary>
468+ /// <param name="stroke">The stroke color.</param>
469+ /// <param name="thickness">The stroke thickness (in device independent units, 1/96 inch).</param>
470+ /// <param name="edgeRenderingMode">The edge rendering mode.</param>
471+ /// <param name="dashArray">The dash array (in device independent units, 1/96 inch). Use <c>null</c> to get a solid line.</param>
472+ /// <param name="lineJoin">The line join type.</param>
473+ /// <returns>A <see cref="Pen"/>, or <code>null</code> if the stroke would be invisible.</returns>
474+ private Pen ? GetPen ( OxyColor stroke , double thickness , double [ ] ? dashArray , EdgeRenderingMode edgeRenderingMode , LineJoin lineJoin )
475+ {
476+ if ( this . IsStrokeInvisible ( stroke , thickness ) )
477+ {
478+ return null ;
479+ }
480+
481+ var actualThickness = this . GetActualThickness ( thickness , edgeRenderingMode ) ;
482+ var actualDashArray = dashArray is null ? null : this . ConvertDashArray ( dashArray , actualThickness ) ;
483+ var actualJointStyle = this . GetLineJointStyle ( lineJoin ) ;
484+
485+ var penOptions = new PenOptions ( ToRgba32 ( stroke ) , actualThickness , actualDashArray )
486+ {
487+ JointStyle = actualJointStyle ,
488+ } ;
489+
490+ return new PatternPen ( penOptions ) ;
491+ }
492+
493+ /// <summary>
494+ /// Converts a <see cref="LineJoin" /> to a <see cref="JointStyle"/>.
495+ /// </summary>
496+ /// <param name="lineJoin">The line join type.</param>
497+ /// <returns>The converted line join style.</returns>
498+ protected JointStyle GetLineJointStyle ( LineJoin lineJoin )
499+ {
500+ switch ( lineJoin )
501+ {
502+ case LineJoin . Miter :
503+ return JointStyle . Miter ;
504+
505+ case LineJoin . Bevel :
506+ return JointStyle . Square ;
507+
508+ case LineJoin . Round :
509+ return JointStyle . Round ;
510+
511+ default :
512+ return JointStyle . Miter ;
513+ }
514+ }
515+
516+ /// <summary>
517+ /// Determines whether the given color and thickness would be invisible.
518+ /// </summary>
519+ /// <param name="stroke">The stroke color.</param>
520+ /// <param name="thickness">The stroke thickness (in device independent units, 1/96 inch).</param>
521+ /// <returns>True if the stroke would be invisible; otherwise false</returns>
522+ protected bool IsStrokeInvisible ( OxyColor stroke , double thickness )
523+ {
524+ return ! stroke . IsVisible ( ) || thickness <= 0 ;
525+ }
526+
431527 /// <inheritdoc/>
432528 protected override void ResetClip ( )
433529 {
@@ -548,14 +644,14 @@ private void Blit(Image<Rgba32> source, Image<Rgba32> destination, Rectangle rec
548644 }
549645 }
550646
551- private Font GetFontOrThrow ( string fontFamily , double fontSize , FontStyle fontWeight , bool allowFallback = true )
647+ private Font GetFontOrThrow ( string ? fontFamily , double fontSize , FontStyle fontWeight , bool allowFallback = true )
552648 {
553649 var family = this . GetFamilyOrFallbackOrThrow ( fontFamily , allowFallback ) ;
554650 var actualFontSize = this . NominalFontSizeToPoints ( fontSize ) ;
555651 return new Font ( family , ( float ) actualFontSize , fontWeight ) ;
556652 }
557653
558- private FontFamily GetFamilyOrFallbackOrThrow ( string fontFamily = null , bool allowFallback = true )
654+ private FontFamily GetFamilyOrFallbackOrThrow ( string ? fontFamily = null , bool allowFallback = true )
559655 {
560656 if ( fontFamily == null )
561657 {
@@ -606,8 +702,8 @@ private OxySize MeasureTextLoose(string text, string fontFamily, double fontSize
606702 var tight = this . MeasureTextTight ( text , fontFamily , fontSize , fontWeight ) ;
607703 var width = tight . Width ;
608704
609- var lineHeight = actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . LineHeight ) ;
610- var lineGap = actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . LineGap ) ;
705+ var lineHeight = actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . VerticalMetrics . LineHeight ) ;
706+ var lineGap = actualFontSize * this . MilliPointsToNominalResolution ( font . FontMetrics . VerticalMetrics . LineGap ) ;
611707 var lineCount = CountLines ( text ) ;
612708
613709 var height = ( lineHeight * lineCount ) + ( lineGap * ( lineCount - 1 ) ) ;
@@ -630,7 +726,7 @@ private OxySize MeasureTextTight(string text, string fontFamily, double fontSize
630726 var font = this . GetFontOrThrow ( fontFamily , fontSize , this . ToFontStyle ( fontWeight ) ) ;
631727 var actualFontSize = this . NominalFontSizeToPoints ( fontSize ) ;
632728
633- var result = TextMeasurer . Measure ( text , new TextOptions ( font ) { Dpi = this . Dpi } ) ;
729+ var result = TextMeasurer . MeasureSize ( text , new TextOptions ( font ) { Dpi = this . Dpi } ) ;
634730 return new OxySize ( this . ConvertBack ( result . Width ) , this . ConvertBack ( result . Height ) ) ;
635731 }
636732
0 commit comments