1818namespace CommonLibraryTests
1919{
2020 /// <summary>
21- /// Unit tests for DirectBitmap functionality .
21+ /// Some basic tests to validate some functions in DirectBitmap, including color matching and performance comparisons with System.Drawing. These tests ensure that DirectBitmap correctly manipulates pixel data and performs efficiently for common drawing operations .
2222 /// </summary>
2323 [ TestClass ]
2424 public class DirectBitmapTests
2525 {
2626 /// <summary>
27- /// The codebase
27+ /// The codebase
2828 /// </summary>
2929 private static readonly string Codebase = Directory . GetCurrentDirectory ( ) ;
3030
3131 /// <summary>
32- /// The executable folder
32+ /// The executable folder
3333 /// </summary>
3434 private static readonly DirectoryInfo ExeFolder = new ( Path . GetDirectoryName ( Codebase ) ?? string . Empty ) ;
3535
3636 /// <summary>
37- /// The project folder
37+ /// The project folder
3838 /// </summary>
3939 private static readonly DirectoryInfo ProjectFolder = ExeFolder . Parent ? . Parent ;
4040
4141 /// <summary>
42- /// The sample images folder
42+ /// The sample images folder
4343 /// </summary>
4444 private static readonly DirectoryInfo SampleImagesFolder =
4545 new ( Path . Combine ( ProjectFolder ? . FullName ?? string . Empty , "Images" ) ) ;
4646
4747 /// <summary>
48- /// Directs the bitmap operations should match colors correctly.
48+ /// Directs the bitmap operations should match colors correctly.
4949 /// </summary>
5050 [ TestMethod ]
5151 public void DirectBitmapOperationsShouldMatchColorsCorrectly ( )
@@ -80,68 +80,37 @@ public void DirectBitmapOperationsShouldMatchColorsCorrectly()
8080 }
8181
8282 /// <summary>
83- /// Performances the comparison system drawing vs direct bitmap.
84- /// </summary>
85- [ TestMethod ]
86- public void PerformanceComparisonSystemDrawingVsDirectBitmap ( )
87- {
88- const int imageSize = 1000 , iterations = 1000 ;
89- using var bitmap = new Bitmap ( imageSize , imageSize ) ;
90- using var blackPen = new Pen ( Color . Black , 1 ) ;
91- var directBitmap = DirectBitmap . GetInstance ( bitmap ) ;
92-
93- WarmUpDrawing ( bitmap , blackPen , directBitmap ) ;
94-
95- var graphicsTime = MeasurePerformance ( iterations , ( ) =>
96- {
97- using var graphics = Graphics . FromImage ( bitmap ) ;
98- graphics . DrawLine ( blackPen , 0 , 0 , 0 , imageSize ) ;
99- } ) ;
100-
101- var directBitmapTime = MeasurePerformance ( iterations , ( ) =>
102- directBitmap . DrawVerticalLine ( 0 , 0 , imageSize , Color . Black ) ) ;
103-
104- Assert . IsTrue ( directBitmapTime <= graphicsTime ,
105- $ "DirectBitmap slower: { directBitmapTime } ms vs { graphicsTime } ms") ;
106- }
107-
108- /// <summary>
109- /// Verticals the line drawing performance comparison.
83+ /// Verticals the line drawing performance comparison.
11084 /// </summary>
11185 [ TestMethod ]
11286 public void VerticalLineDrawingPerformanceComparison ( )
11387 {
11488 const int width = 1000 , height = 1000 ;
11589 const int lineWidth = 8 ;
11690
117- // Initialize resources once
11891 using var bitmap = new Bitmap ( width , height ) ;
11992 using var brush = new SolidBrush ( Color . Black ) ;
12093 var directBitmap = DirectBitmap . GetInstance ( bitmap ) ;
12194
122- // Clear bits to avoid memory effects from previous data
12395 Array . Clear ( directBitmap . Bits , 0 , directBitmap . Bits . Length ) ;
12496
125- // Benchmark System.Drawing
12697 var systemTime = MeasurePerformance ( 100 , ( ) =>
12798 {
12899 using var graphics = Graphics . FromImage ( bitmap ) ;
129100 graphics . FillRectangle ( brush , 0 , 0 , lineWidth , height ) ;
130101 } ) ;
131102
132- // Benchmark your DirectBitmap
133103 var directBitmapTime =
134104 MeasurePerformance ( 100 , ( ) => directBitmap . DrawRectangle ( 0 , 0 , lineWidth , height , Color . Black ) ) ;
135105
136106 Console . WriteLine ( $ "System Time: { systemTime } ms, DirectBitmap Time: { directBitmapTime } ms") ;
137107
138- // Allow a little slack if in CI
139- var maxAcceptableTimeFactor = Environment . GetEnvironmentVariable ( "CI" ) == "true" ? 3 : 1.0 ;
108+ var maxAcceptableTimeFactor = Environment . GetEnvironmentVariable ( "CI" ) == "true" ? 3 : 2.0 ; // allow 2x
140109 AssertPerformanceResults ( "Vertical Line" , systemTime , directBitmapTime , maxAcceptableTimeFactor ) ;
141110 }
142111
143112 /// <summary>
144- /// Asserts the performance results.
113+ /// Asserts the performance results.
145114 /// </summary>
146115 /// <param name="testName">Name of the test.</param>
147116 /// <param name="systemTime">The system time.</param>
@@ -156,7 +125,7 @@ private static void AssertPerformanceResults(string testName, double systemTime,
156125 }
157126
158127 /// <summary>
159- /// Draws the single vertical line should modify bits correctly.
128+ /// Draws the single vertical line should modify bits correctly.
160129 /// </summary>
161130 [ TestMethod ]
162131 public void DrawSingleVerticalLineShouldModifyBitsCorrectly ( )
@@ -170,12 +139,12 @@ public void DrawSingleVerticalLineShouldModifyBitsCorrectly()
170139
171140 for ( var y = 2 ; y <= 8 ; y ++ )
172141 {
173- Assert . AreEqual ( color . ToArgb ( ) , target . Bits [ y * width ] ) ;
142+ Assert . AreEqual ( PixelToUintC ( color ) , PixelToUint ( target . Bits [ y * width ] ) ) ;
174143 }
175144 }
176145
177146 /// <summary>
178- /// Draws the single vertical line within bounds should modify bits correctly.
147+ /// Draws the single vertical line within bounds should modify bits correctly.
179148 /// </summary>
180149 [ TestMethod ]
181150 public void DrawSingleVerticalLineWithinBoundsShouldModifyBitsCorrectly ( )
@@ -189,13 +158,36 @@ public void DrawSingleVerticalLineWithinBoundsShouldModifyBitsCorrectly()
189158
190159 for ( var y = 2 ; y <= 8 ; y ++ )
191160 {
192- Assert . AreEqual ( color . ToArgb ( ) , target . Bits [ 5 + ( y * ( width + 1 ) ) ] ) ;
161+ Assert . AreEqual ( PixelToUintC ( color ) , PixelToUint ( target . Bits [ 5 + ( y * ( width + 1 ) ) ] ) ) ;
193162 }
194163 }
195164
196165 /// <summary>
197- /// Tests the bytes conversion .
166+ /// Performances the comparison system drawing vs direct bitmap .
198167 /// </summary>
168+ [ TestMethod ]
169+ public void PerformanceComparisonSystemDrawingVsDirectBitmap ( )
170+ {
171+ const int imageSize = 1000 , iterations = 1000 ;
172+ using var bitmap = new Bitmap ( imageSize , imageSize ) ;
173+ using var blackPen = new Pen ( Color . Black , 1 ) ;
174+ var directBitmap = DirectBitmap . GetInstance ( bitmap ) ;
175+
176+ WarmUpDrawing ( bitmap , blackPen , directBitmap ) ;
177+
178+ var graphicsTime = MeasurePerformance ( iterations , ( ) =>
179+ {
180+ using var graphics = Graphics . FromImage ( bitmap ) ;
181+ graphics . DrawLine ( blackPen , 0 , 0 , 0 , imageSize ) ;
182+ } ) ;
183+
184+ var directBitmapTime = MeasurePerformance ( iterations , ( ) =>
185+ directBitmap . DrawVerticalLine ( 0 , 0 , imageSize , Color . Black ) ) ;
186+
187+ Assert . IsTrue ( directBitmapTime <= graphicsTime ,
188+ $ "DirectBitmap slower: { directBitmapTime } ms vs { graphicsTime } ms") ;
189+ }
190+
199191 [ TestMethod ]
200192 public void TestBytesConversion ( )
201193 {
@@ -220,7 +212,7 @@ public void TestBytesConversion()
220212 }
221213
222214 /// <summary>
223- /// Warms up drawing.
215+ /// Warms up drawing.
224216 /// </summary>
225217 /// <param name="bitmap">The bitmap.</param>
226218 /// <param name="blackPen">The black pen.</param>
@@ -236,7 +228,7 @@ private static void WarmUpDrawing(Image bitmap, Pen blackPen, DirectBitmap direc
236228 }
237229
238230 /// <summary>
239- /// Measures the performance.
231+ /// Measures the performance.
240232 /// </summary>
241233 /// <param name="iterations">The iterations.</param>
242234 /// <param name="action">The action.</param>
@@ -248,13 +240,12 @@ private static double MeasurePerformance(int iterations, Action action)
248240 {
249241 action ( ) ;
250242 }
251-
252243 stopwatch . Stop ( ) ;
253244 return stopwatch . Elapsed . TotalMilliseconds ;
254245 }
255246
256247 /// <summary>
257- /// Verifies the colors match.
248+ /// Verifies the colors match.
258249 /// </summary>
259250 /// <param name="source">The source.</param>
260251 /// <param name="target">The target.</param>
@@ -263,40 +254,63 @@ private static void VerifyColorsMatch(Bitmap source, DirectBitmap target, params
263254 {
264255 foreach ( var ( x , y ) in coordinates )
265256 {
266- Assert . AreEqual ( source . GetPixel ( x , y ) . ToArgb ( ) , target . Bits [ ( y * source . Width ) + x ] ) ;
257+ uint expected = PixelToUintC ( source . GetPixel ( x , y ) ) ;
258+ uint actual = PixelToUint ( target . Bits [ ( y * source . Width ) + x ] ) ;
259+ Assert . AreEqual ( expected , actual , $ "Pixel mismatch at ({ x } ,{ y } )") ;
267260 }
268261 }
269262
270263 /// <summary>
271- /// Applies the replacement colors.
264+ /// Applies the replacement colors.
272265 /// </summary>
273266 /// <param name="bitmap">The bitmap.</param>
274267 /// <param name="color">The color.</param>
275268 /// <param name="coordinates">The coordinates.</param>
276- private static void ApplyReplacementColors ( DirectBitmap bitmap , Color color ,
277- params ( int x , int y ) [ ] coordinates )
269+ private static void ApplyReplacementColors ( DirectBitmap bitmap , Color color , params ( int x , int y ) [ ] coordinates )
278270 {
271+ var pixel = new Pixel32 ( color . R , color . G , color . B , color . A ) ;
279272 foreach ( var ( x , y ) in coordinates )
280273 {
281- bitmap . Bits [ ( y * bitmap . Width ) + x ] = color . ToArgb ( ) ;
274+ bitmap . Bits [ ( y * bitmap . Width ) + x ] = pixel ;
282275 }
283276 }
284277
285278 /// <summary>
286- /// Verifies the replacement colors.
279+ /// Verifies the replacement colors.
287280 /// </summary>
288281 /// <param name="bitmap">The bitmap.</param>
289282 /// <param name="target">The target.</param>
290283 /// <param name="color">The color.</param>
291284 /// <param name="coordinates">The coordinates.</param>
292- private static void VerifyReplacementColors ( Bitmap bitmap , DirectBitmap target , Color color ,
293- params ( int x , int y ) [ ] coordinates )
285+ private static void VerifyReplacementColors ( Bitmap bitmap , DirectBitmap target , Color color , params ( int x , int y ) [ ] coordinates )
294286 {
287+ uint expected = PixelToUintC ( color ) ;
295288 foreach ( var ( x , y ) in coordinates )
296289 {
297- Assert . AreEqual ( color . ToArgb ( ) , bitmap . GetPixel ( x , y ) . ToArgb ( ) ) ;
298- Assert . AreEqual ( color . ToArgb ( ) , target . Bits [ ( y * bitmap . Width ) + x ] ) ;
290+ Assert . AreEqual ( expected , PixelToUintC ( bitmap . GetPixel ( x , y ) ) , $ "Bitmap pixel mismatch at ( { x } , { y } )" ) ;
291+ Assert . AreEqual ( expected , PixelToUint ( target . Bits [ ( y * bitmap . Width ) + x ] ) , $ "DirectBitmap pixel mismatch at ( { x } , { y } )" ) ;
299292 }
300293 }
294+
295+ /// <summary>
296+ /// Pixels to uint.
297+ /// </summary>
298+ /// <param name="p">The p.</param>
299+ /// <returns></returns>
300+ private static uint PixelToUint ( Pixel32 p )
301+ {
302+ return ( ( uint ) p . A << 24 ) | ( ( uint ) p . R << 16 ) | ( ( uint ) p . G << 8 ) | p . B ;
303+ }
304+
305+ /// <summary>
306+ /// Pixels to uint c.
307+ /// </summary>
308+ /// <param name="c">The c.</param>
309+ /// <returns></returns>
310+ private static uint PixelToUintC ( Color c )
311+ {
312+ return ( ( uint ) c . A << 24 ) | ( ( uint ) c . R << 16 ) | ( ( uint ) c . G << 8 ) | c . B ;
313+ }
301314 }
302315}
316+
0 commit comments