@@ -82,20 +82,49 @@ public static bool ImagesAreEqual(Stream actual, Stream expected)
82
82
/// <param name="expected"></param>
83
83
/// <returns>True if every pixel of actual is equal to expected</returns>
84
84
public static bool ImagesAreEqual ( Image actual , Image expected )
85
+ {
86
+ var ownsActual = false ;
87
+ var ownsExpected = false ;
88
+ Image < Rgb24 > ? actualPixelaccessableImage = null ;
89
+ Image < Rgb24 > ? expectedPixelaccessableImage = null ;
90
+ try
91
+ {
92
+ actualPixelaccessableImage = ToRgb24Image ( actual , out ownsActual ) ;
93
+ expectedPixelaccessableImage = ToRgb24Image ( expected , out ownsExpected ) ;
94
+
95
+ return ImagesAreEqual ( actualPixelaccessableImage , expectedPixelaccessableImage ) ;
96
+ }
97
+ finally
98
+ {
99
+ if ( ownsActual )
100
+ {
101
+ actualPixelaccessableImage ? . Dispose ( ) ;
102
+ }
103
+ if ( ownsExpected )
104
+ {
105
+ expectedPixelaccessableImage ? . Dispose ( ) ;
106
+ }
107
+ }
108
+ }
109
+
110
+ /// <summary>
111
+ /// Compares two images for equivalence
112
+ /// </summary>
113
+ /// <param name="actual"></param>
114
+ /// <param name="expected"></param>
115
+ /// <returns>True if every pixel of actual is equal to expected</returns>
116
+ public static bool ImagesAreEqual ( Image < Rgb24 > actual , Image < Rgb24 > expected )
85
117
{
86
118
if ( ! ImagesHaveSameDimension ( actual , expected ) )
87
119
{
88
120
return false ;
89
121
}
90
122
91
- using var actualPixelaccessableImage = ToRgb24Image ( actual ) ;
92
- using var expectedPixelaccessableImage = ToRgb24Image ( expected ) ;
93
-
94
123
for ( var x = 0 ; x < actual . Width ; x ++ )
95
124
{
96
125
for ( var y = 0 ; y < actual . Height ; y ++ )
97
126
{
98
- if ( ! actualPixelaccessableImage [ x , y ] . Equals ( expectedPixelaccessableImage [ x , y ] ) )
127
+ if ( ! actual [ x , y ] . Equals ( expected [ x , y ] ) )
99
128
{
100
129
return false ;
101
130
}
@@ -138,15 +167,45 @@ public static ICompareResult CalcDiff(Stream actualImage, Stream expectedImage)
138
167
/// <param name="expected"></param>
139
168
/// <returns>Mean and absolute pixel error</returns>
140
169
public static ICompareResult CalcDiff ( Image actual , Image expected )
170
+ {
171
+ var ownsActual = false ;
172
+ var ownsExpected = false ;
173
+ Image < Rgb24 > ? actualRgb24 = null ;
174
+ Image < Rgb24 > ? expectedRgb24 = null ;
175
+
176
+ try
177
+ {
178
+ actualRgb24 = ToRgb24Image ( actual , out ownsActual ) ;
179
+ expectedRgb24 = ToRgb24Image ( expected , out ownsExpected ) ;
180
+
181
+ return CalcDiff ( actualRgb24 , expectedRgb24 ) ;
182
+ }
183
+ finally
184
+ {
185
+ if ( ownsActual )
186
+ {
187
+ actualRgb24 ? . Dispose ( ) ;
188
+ }
189
+ if ( ownsExpected )
190
+ {
191
+ expectedRgb24 ? . Dispose ( ) ;
192
+ }
193
+ }
194
+ }
195
+
196
+ /// <summary>
197
+ /// Calculates ICompareResult expressing the amount of difference of both images
198
+ /// </summary>
199
+ /// <param name="actual"></param>
200
+ /// <param name="expected"></param>
201
+ /// <returns>Mean and absolute pixel error</returns>
202
+ public static ICompareResult CalcDiff ( Image < Rgb24 > actual , Image < Rgb24 > expected )
141
203
{
142
204
if ( ! ImagesHaveSameDimension ( actual , expected ) )
143
205
{
144
206
throw new ImageSharpCompareException ( sizeDiffersExceptionMessage ) ;
145
207
}
146
208
147
- using var actualRgb24 = ToRgb24Image ( actual ) ;
148
- using var expectedRgb24 = ToRgb24Image ( expected ) ;
149
-
150
209
var quantity = actual . Width * actual . Height ;
151
210
var absoluteError = 0 ;
152
211
var pixelErrorCount = 0 ;
@@ -155,9 +214,12 @@ public static ICompareResult CalcDiff(Image actual, Image expected)
155
214
{
156
215
for ( var y = 0 ; y < actual . Height ; y ++ )
157
216
{
158
- var r = Math . Abs ( expectedRgb24 [ x , y ] . R - actualRgb24 [ x , y ] . R ) ;
159
- var g = Math . Abs ( expectedRgb24 [ x , y ] . G - actualRgb24 [ x , y ] . G ) ;
160
- var b = Math . Abs ( expectedRgb24 [ x , y ] . B - actualRgb24 [ x , y ] . B ) ;
217
+ var actualPixel = actual [ x , y ] ;
218
+ var expectedPixel = expected [ x , y ] ;
219
+
220
+ var r = Math . Abs ( expectedPixel . R - actualPixel . R ) ;
221
+ var g = Math . Abs ( expectedPixel . G - actualPixel . G ) ;
222
+ var b = Math . Abs ( expectedPixel . B - actualPixel . B ) ;
161
223
absoluteError = absoluteError + r + g + b ;
162
224
163
225
pixelErrorCount += r + g + b > 0 ? 1 : 0 ;
@@ -213,22 +275,28 @@ private static bool ImagesHaveSameDimension(Image actual, Image expected)
213
275
return actual . Height == expected . Height && actual . Width == expected . Width ;
214
276
}
215
277
216
- private static Image < Rgb24 > ToRgb24Image ( Image actual )
278
+ private static Image < Rgb24 > ToRgb24Image ( Image actual , out bool ownsImage )
217
279
{
218
280
if ( actual is Image < Rgb24 > actualPixelaccessableImage )
219
281
{
282
+ ownsImage = false ;
220
283
return actualPixelaccessableImage ;
221
284
}
222
285
223
286
if ( actual is Image < Rgba32 > imageRgba32 )
224
287
{
225
- return Rgba32ToRgb24 ( imageRgba32 ) ;
288
+ ownsImage = true ;
289
+ return ConvertRgba32ToRgb24 ( imageRgba32 ) ;
226
290
}
227
291
228
292
throw new NotImplementedException ( $ "Pixel type { actual . PixelType } is not supported to be compared.") ;
229
293
}
230
294
231
- private static Image < Rgb24 > Rgba32ToRgb24 ( Image < Rgba32 > imageRgba32 )
295
+ /// <summary>
296
+ /// Converts a Rgba32 Image to Rgb24 one
297
+ /// </summary>
298
+ /// <param name="imageRgba32"></param>
299
+ public static Image < Rgb24 > ConvertRgba32ToRgb24 ( Image < Rgba32 > imageRgba32 )
232
300
{
233
301
var maskRgb24 = new Image < Rgb24 > ( imageRgba32 . Width , imageRgba32 . Height ) ;
234
302
@@ -253,6 +321,47 @@ private static Image<Rgb24> Rgba32ToRgb24(Image<Rgba32> imageRgba32)
253
321
/// <param name="maskImage"></param>
254
322
/// <returns>Mean and absolute pixel error</returns>
255
323
public static ICompareResult CalcDiff ( Image actual , Image expected , Image maskImage )
324
+ {
325
+ var ownsActual = false ;
326
+ var ownsExpected = false ;
327
+ var ownsMask = false ;
328
+ Image < Rgb24 > ? actualRgb24 = null ;
329
+ Image < Rgb24 > ? expectedRgb24 = null ;
330
+ Image < Rgb24 > ? maskImageRgb24 = null ;
331
+
332
+ try
333
+ {
334
+ actualRgb24 = ToRgb24Image ( actual , out ownsActual ) ;
335
+ expectedRgb24 = ToRgb24Image ( expected , out ownsExpected ) ;
336
+ maskImageRgb24 = ToRgb24Image ( maskImage , out ownsMask ) ;
337
+
338
+ return CalcDiff ( actualRgb24 , expectedRgb24 , maskImageRgb24 ) ;
339
+ }
340
+ finally
341
+ {
342
+ if ( ownsActual )
343
+ {
344
+ actualRgb24 ? . Dispose ( ) ;
345
+ }
346
+ if ( ownsExpected )
347
+ {
348
+ expectedRgb24 ? . Dispose ( ) ;
349
+ }
350
+ if ( ownsMask )
351
+ {
352
+ maskImageRgb24 ? . Dispose ( ) ;
353
+ }
354
+ }
355
+ }
356
+
357
+ /// <summary>
358
+ /// Calculates ICompareResult expressing the amount of difference of both images using a image mask for tolerated difference between the two images
359
+ /// </summary>
360
+ /// <param name="actual"></param>
361
+ /// <param name="expected"></param>
362
+ /// <param name="maskImage"></param>
363
+ /// <returns>Mean and absolute pixel error</returns>
364
+ public static ICompareResult CalcDiff ( Image < Rgb24 > actual , Image < Rgb24 > expected , Image < Rgb24 > maskImage )
256
365
{
257
366
if ( ! ImagesHaveSameDimension ( actual , expected ) )
258
367
{
@@ -268,18 +377,17 @@ public static ICompareResult CalcDiff(Image actual, Image expected, Image maskIm
268
377
var absoluteError = 0 ;
269
378
var pixelErrorCount = 0 ;
270
379
271
- using var actualRgb24 = ToRgb24Image ( actual ) ;
272
- using var expectedRgb24 = ToRgb24Image ( expected ) ;
273
- using var maskImageRgb24 = ToRgb24Image ( maskImage ) ;
274
-
275
380
for ( var x = 0 ; x < actual . Width ; x ++ )
276
381
{
277
382
for ( var y = 0 ; y < actual . Height ; y ++ )
278
383
{
279
- var maskImagePixel = maskImageRgb24 [ x , y ] ;
280
- var r = Math . Abs ( expectedRgb24 [ x , y ] . R - actualRgb24 [ x , y ] . R ) ;
281
- var g = Math . Abs ( expectedRgb24 [ x , y ] . G - actualRgb24 [ x , y ] . G ) ;
282
- var b = Math . Abs ( expectedRgb24 [ x , y ] . B - actualRgb24 [ x , y ] . B ) ;
384
+ var maskImagePixel = maskImage [ x , y ] ;
385
+ var actualPixel = actual [ x , y ] ;
386
+ var expectedPixel = expected [ x , y ] ;
387
+
388
+ var r = Math . Abs ( expectedPixel . R - actualPixel . R ) ;
389
+ var g = Math . Abs ( expectedPixel . G - actualPixel . G ) ;
390
+ var b = Math . Abs ( expectedPixel . B - actualPixel . B ) ;
283
391
284
392
var error = 0 ;
285
393
@@ -340,26 +448,59 @@ public static Image CalcDiffMaskImage(Stream actualImage, Stream expectedImage)
340
448
/// <param name="expected"></param>
341
449
/// <returns>Image representing diff, black means no diff between actual image and expected image, white means max diff</returns>
342
450
public static Image CalcDiffMaskImage ( Image actual , Image expected )
451
+ {
452
+ var ownsActual = false ;
453
+ var ownsExpected = false ;
454
+ Image < Rgb24 > ? actualRgb24 = null ;
455
+ Image < Rgb24 > ? expectedRgb24 = null ;
456
+
457
+ try
458
+ {
459
+ actualRgb24 = ToRgb24Image ( actual , out ownsActual ) ;
460
+ expectedRgb24 = ToRgb24Image ( expected , out ownsExpected ) ;
461
+
462
+ return CalcDiffMaskImage ( actualRgb24 , expectedRgb24 ) ;
463
+ }
464
+ finally
465
+ {
466
+ if ( ownsActual )
467
+ {
468
+ actualRgb24 ? . Dispose ( ) ;
469
+ }
470
+ if ( ownsExpected )
471
+ {
472
+ expectedRgb24 ? . Dispose ( ) ;
473
+ }
474
+ }
475
+ }
476
+
477
+ /// <summary>
478
+ /// Creates a diff mask image of two images
479
+ /// </summary>
480
+ /// <param name="actual"></param>
481
+ /// <param name="expected"></param>
482
+ /// <returns>Image representing diff, black means no diff between actual image and expected image, white means max diff</returns>
483
+ public static Image CalcDiffMaskImage ( Image < Rgb24 > actual , Image < Rgb24 > expected )
343
484
{
344
485
if ( ! ImagesHaveSameDimension ( actual , expected ) )
345
486
{
346
487
throw new ImageSharpCompareException ( sizeDiffersExceptionMessage ) ;
347
488
}
348
489
349
- using var actualRgb24 = ToRgb24Image ( actual ) ;
350
- using var expectedRgb24 = ToRgb24Image ( expected ) ;
351
-
352
490
var maskImage = new Image < Rgb24 > ( actual . Width , actual . Height ) ;
353
491
354
492
for ( var x = 0 ; x < actual . Width ; x ++ )
355
493
{
356
494
for ( var y = 0 ; y < actual . Height ; y ++ )
357
495
{
496
+ var actualPixel = actual [ x , y ] ;
497
+ var expectedPixel = expected [ x , y ] ;
498
+
358
499
var pixel = new Rgb24
359
500
{
360
- R = ( byte ) Math . Abs ( actualRgb24 [ x , y ] . R - expectedRgb24 [ x , y ] . R ) ,
361
- G = ( byte ) Math . Abs ( actualRgb24 [ x , y ] . G - expectedRgb24 [ x , y ] . G ) ,
362
- B = ( byte ) Math . Abs ( actualRgb24 [ x , y ] . B - expectedRgb24 [ x , y ] . B )
501
+ R = ( byte ) Math . Abs ( actualPixel . R - expectedPixel . R ) ,
502
+ G = ( byte ) Math . Abs ( actualPixel . G - expectedPixel . G ) ,
503
+ B = ( byte ) Math . Abs ( actualPixel . B - expectedPixel . B )
363
504
} ;
364
505
365
506
maskImage [ x , y ] = pixel ;
0 commit comments