@@ -8,6 +8,127 @@ namespace SixLabors.ImageSharp.Drawing.Tests.Processing;
88
99public partial class DrawingCanvasTests
1010{
11+ [ Theory ]
12+ [ WithBlankImage ( 50 , 50 , PixelTypes . Rgba32 ) ]
13+ public void FillRectangle_AliasedRendersFullCorners < TPixel > ( TestImageProvider < TPixel > provider )
14+ where TPixel : unmanaged, IPixel < TPixel >
15+ {
16+ const int x = 10 ;
17+ const int y = 10 ;
18+ const int w = 30 ;
19+ const int h = 20 ;
20+
21+ DrawingOptions options = new ( )
22+ {
23+ GraphicsOptions = new GraphicsOptions { Antialias = false }
24+ } ;
25+
26+ using Image < TPixel > target = provider . GetImage ( ) ;
27+ using DrawingCanvas < TPixel > canvas = CreateCanvas ( provider , target , options ) ;
28+
29+ canvas . Clear ( Brushes . Solid ( Color . Black ) ) ;
30+ canvas . Fill ( Brushes . Solid ( Color . White ) , new Rectangle ( x , y , w , h ) ) ;
31+ canvas . Flush ( ) ;
32+
33+ target . DebugSave ( provider , appendSourceFileOrDescription : false ) ;
34+
35+ // Verify all four corner pixels are fully white.
36+ Rgba32 topLeft = target [ x , y ] . ToRgba32 ( ) ;
37+ Rgba32 topRight = target [ x + w - 1 , y ] . ToRgba32 ( ) ;
38+ Rgba32 bottomLeft = target [ x , y + h - 1 ] . ToRgba32 ( ) ;
39+ Rgba32 bottomRight = target [ x + w - 1 , y + h - 1 ] . ToRgba32 ( ) ;
40+
41+ Assert . Equal ( 255 , topLeft . R ) ;
42+ Assert . Equal ( 255 , topRight . R ) ;
43+ Assert . Equal ( 255 , bottomLeft . R ) ;
44+ Assert . Equal ( 255 , bottomRight . R ) ;
45+
46+ // Verify pixels just outside each corner are still black.
47+ Assert . Equal ( 0 , target [ x - 1 , y ] . ToRgba32 ( ) . R ) ;
48+ Assert . Equal ( 0 , target [ x , y - 1 ] . ToRgba32 ( ) . R ) ;
49+ Assert . Equal ( 0 , target [ x + w , y ] . ToRgba32 ( ) . R ) ;
50+ Assert . Equal ( 0 , target [ x + w - 1 , y - 1 ] . ToRgba32 ( ) . R ) ;
51+ Assert . Equal ( 0 , target [ x - 1 , y + h - 1 ] . ToRgba32 ( ) . R ) ;
52+ Assert . Equal ( 0 , target [ x , y + h ] . ToRgba32 ( ) . R ) ;
53+ Assert . Equal ( 0 , target [ x + w , y + h - 1 ] . ToRgba32 ( ) . R ) ;
54+ Assert . Equal ( 0 , target [ x + w - 1 , y + h ] . ToRgba32 ( ) . R ) ;
55+
56+ // Verify interior pixel count matches expected area.
57+ int whiteCount = 0 ;
58+ target . ProcessPixelRows ( accessor =>
59+ {
60+ for ( int row = 0 ; row < accessor . Height ; row ++ )
61+ {
62+ Span < TPixel > span = accessor . GetRowSpan ( row ) ;
63+ for ( int col = 0 ; col < span . Length ; col ++ )
64+ {
65+ if ( span [ col ] . ToRgba32 ( ) . R == 255 )
66+ {
67+ whiteCount ++ ;
68+ }
69+ }
70+ }
71+ } ) ;
72+
73+ Assert . Equal ( w * h , whiteCount ) ;
74+ }
75+
76+ [ Theory ]
77+ [ WithBlankImage ( 50 , 50 , PixelTypes . Rgba32 ) ]
78+ public void DrawRectangle_AliasedRendersFullCorners < TPixel > ( TestImageProvider < TPixel > provider )
79+ where TPixel : unmanaged, IPixel < TPixel >
80+ {
81+ // A 2px pen centered on the rectangle edge places 1px inside and 1px outside.
82+ // For a rect at (10,10) size 30x20, the outer stroke boundary is (9,9)-(40,30)
83+ // and the inner boundary is (11,11)-(38,28).
84+ // Miter join ensures corners are fully filled (bevel would cut them).
85+ const int x = 10 ;
86+ const int y = 10 ;
87+ const int w = 30 ;
88+ const int h = 20 ;
89+ const float penWidth = 2 ;
90+
91+ DrawingOptions options = new ( )
92+ {
93+ GraphicsOptions = new GraphicsOptions { Antialias = false , AntialiasThreshold = 0.01F }
94+ } ;
95+
96+ SolidPen pen = new ( new PenOptions ( Color . White , penWidth , null )
97+ {
98+ StrokeOptions = new StrokeOptions { LineJoin = LineJoin . Miter }
99+ } ) ;
100+
101+ using Image < TPixel > target = provider . GetImage ( ) ;
102+ using DrawingCanvas < TPixel > canvas = CreateCanvas ( provider , target , options ) ;
103+
104+ canvas . Clear ( Brushes . Solid ( Color . Black ) ) ;
105+ canvas . Draw ( pen , new Rectangle ( x , y , w , h ) ) ;
106+ canvas . Flush ( ) ;
107+
108+ target . DebugSave ( provider , appendSourceFileOrDescription : false ) ;
109+
110+ // Outer corners of the stroke (1px outside the rect edge).
111+ Assert . Equal ( 255 , target [ x - 1 , y - 1 ] . ToRgba32 ( ) . R ) ;
112+ Assert . Equal ( 255 , target [ x + w , y - 1 ] . ToRgba32 ( ) . R ) ;
113+ Assert . Equal ( 255 , target [ x - 1 , y + h ] . ToRgba32 ( ) . R ) ;
114+ Assert . Equal ( 255 , target [ x + w , y + h ] . ToRgba32 ( ) . R ) ;
115+
116+ // Inner corners of the stroke (1px inside the rect edge).
117+ Assert . Equal ( 255 , target [ x , y ] . ToRgba32 ( ) . R ) ;
118+ Assert . Equal ( 255 , target [ x + w - 1 , y ] . ToRgba32 ( ) . R ) ;
119+ Assert . Equal ( 255 , target [ x , y + h - 1 ] . ToRgba32 ( ) . R ) ;
120+ Assert . Equal ( 255 , target [ x + w - 1 , y + h - 1 ] . ToRgba32 ( ) . R ) ;
121+
122+ // Well outside the stroke boundary should be black.
123+ Assert . Equal ( 0 , target [ x - 3 , y - 3 ] . ToRgba32 ( ) . R ) ;
124+ Assert . Equal ( 0 , target [ x + w + 2 , y - 3 ] . ToRgba32 ( ) . R ) ;
125+ Assert . Equal ( 0 , target [ x - 3 , y + h + 2 ] . ToRgba32 ( ) . R ) ;
126+ Assert . Equal ( 0 , target [ x + w + 2 , y + h + 2 ] . ToRgba32 ( ) . R ) ;
127+
128+ // Interior of the rectangle (well inside the stroke) should be black.
129+ Assert . Equal ( 0 , target [ x + ( w / 2 ) , y + ( h / 2 ) ] . ToRgba32 ( ) . R ) ;
130+ }
131+
11132 [ Theory ]
12133 [ WithBlankImage ( 240 , 160 , PixelTypes . Rgba32 ) ]
13134 public void DrawPrimitiveHelpers_MatchesReference < TPixel > ( TestImageProvider < TPixel > provider )
0 commit comments