Skip to content

Commit a052089

Browse files
authored
Bump SixLabors.ImageSharp from 2.1.2 to 2.1.3
Bugfix - No more disposing of Image<Rgb24> input Exposed ConvertRgba32ToRgb24 Performance improvements
2 parents ce17a31 + 1719c50 commit a052089

File tree

7 files changed

+272
-79
lines changed

7 files changed

+272
-79
lines changed

.editorconfig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@ csharp_style_var_when_type_is_apparent = true:warning
1010

1111
[*.{cs,vb}]
1212
tab_width=4
13-
indent_size=4
13+
indent_size=4
14+
15+
# Code-block preferences - reflecting codacy defaults
16+
csharp_prefer_braces = true:warning
17+
18+
# IDE0011: Add braces - reflecting codacy defaults
19+
dotnet_diagnostic.IDE0011.severity = warning

.github/workflows/dotnet.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ jobs:
8181
ls ./ImageSharpCompare/bin/Release
8282
dotnet nuget push ./ImageSharpCompare/bin/Release/*.nupkg --skip-duplicate --api-key ${{secrets.NUGET_TEST_TOKEN}} --source https://apiint.nugettest.org/v3/index.json
8383
- uses: "marvinpinto/action-automatic-releases@latest"
84+
if: github.ref == 'refs/heads/main'
8485
with:
8586
repo_token: "${{ secrets.GITHUB_TOKEN }}"
8687
automatic_release_tag: "latest-prerelease"

ImageSharpCompare/ImageSharpCompare.cs

Lines changed: 168 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,49 @@ public static bool ImagesAreEqual(Stream actual, Stream expected)
8282
/// <param name="expected"></param>
8383
/// <returns>True if every pixel of actual is equal to expected</returns>
8484
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)
85117
{
86118
if (!ImagesHaveSameDimension(actual, expected))
87119
{
88120
return false;
89121
}
90122

91-
using var actualPixelaccessableImage = ToRgb24Image(actual);
92-
using var expectedPixelaccessableImage = ToRgb24Image(expected);
93-
94123
for (var x = 0; x < actual.Width; x++)
95124
{
96125
for (var y = 0; y < actual.Height; y++)
97126
{
98-
if (!actualPixelaccessableImage[x, y].Equals(expectedPixelaccessableImage[x, y]))
127+
if (!actual[x, y].Equals(expected[x, y]))
99128
{
100129
return false;
101130
}
@@ -138,15 +167,45 @@ public static ICompareResult CalcDiff(Stream actualImage, Stream expectedImage)
138167
/// <param name="expected"></param>
139168
/// <returns>Mean and absolute pixel error</returns>
140169
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)
141203
{
142204
if (!ImagesHaveSameDimension(actual, expected))
143205
{
144206
throw new ImageSharpCompareException(sizeDiffersExceptionMessage);
145207
}
146208

147-
using var actualRgb24 = ToRgb24Image(actual);
148-
using var expectedRgb24 = ToRgb24Image(expected);
149-
150209
var quantity = actual.Width * actual.Height;
151210
var absoluteError = 0;
152211
var pixelErrorCount = 0;
@@ -155,9 +214,12 @@ public static ICompareResult CalcDiff(Image actual, Image expected)
155214
{
156215
for (var y = 0; y < actual.Height; y++)
157216
{
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);
161223
absoluteError = absoluteError + r + g + b;
162224

163225
pixelErrorCount += r + g + b > 0 ? 1 : 0;
@@ -213,22 +275,28 @@ private static bool ImagesHaveSameDimension(Image actual, Image expected)
213275
return actual.Height == expected.Height && actual.Width == expected.Width;
214276
}
215277

216-
private static Image<Rgb24> ToRgb24Image(Image actual)
278+
private static Image<Rgb24> ToRgb24Image(Image actual, out bool ownsImage)
217279
{
218280
if (actual is Image<Rgb24> actualPixelaccessableImage)
219281
{
282+
ownsImage = false;
220283
return actualPixelaccessableImage;
221284
}
222285

223286
if (actual is Image<Rgba32> imageRgba32)
224287
{
225-
return Rgba32ToRgb24(imageRgba32);
288+
ownsImage = true;
289+
return ConvertRgba32ToRgb24(imageRgba32);
226290
}
227291

228292
throw new NotImplementedException($"Pixel type {actual.PixelType} is not supported to be compared.");
229293
}
230294

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)
232300
{
233301
var maskRgb24 = new Image<Rgb24>(imageRgba32.Width, imageRgba32.Height);
234302

@@ -253,6 +321,47 @@ private static Image<Rgb24> Rgba32ToRgb24(Image<Rgba32> imageRgba32)
253321
/// <param name="maskImage"></param>
254322
/// <returns>Mean and absolute pixel error</returns>
255323
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)
256365
{
257366
if (!ImagesHaveSameDimension(actual, expected))
258367
{
@@ -268,18 +377,17 @@ public static ICompareResult CalcDiff(Image actual, Image expected, Image maskIm
268377
var absoluteError = 0;
269378
var pixelErrorCount = 0;
270379

271-
using var actualRgb24 = ToRgb24Image(actual);
272-
using var expectedRgb24 = ToRgb24Image(expected);
273-
using var maskImageRgb24 = ToRgb24Image(maskImage);
274-
275380
for (var x = 0; x < actual.Width; x++)
276381
{
277382
for (var y = 0; y < actual.Height; y++)
278383
{
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);
283391

284392
var error = 0;
285393

@@ -340,26 +448,59 @@ public static Image CalcDiffMaskImage(Stream actualImage, Stream expectedImage)
340448
/// <param name="expected"></param>
341449
/// <returns>Image representing diff, black means no diff between actual image and expected image, white means max diff</returns>
342450
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)
343484
{
344485
if (!ImagesHaveSameDimension(actual, expected))
345486
{
346487
throw new ImageSharpCompareException(sizeDiffersExceptionMessage);
347488
}
348489

349-
using var actualRgb24 = ToRgb24Image(actual);
350-
using var expectedRgb24 = ToRgb24Image(expected);
351-
352490
var maskImage = new Image<Rgb24>(actual.Width, actual.Height);
353491

354492
for (var x = 0; x < actual.Width; x++)
355493
{
356494
for (var y = 0; y < actual.Height; y++)
357495
{
496+
var actualPixel = actual[x, y];
497+
var expectedPixel = expected[x, y];
498+
358499
var pixel = new Rgb24
359500
{
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)
363504
};
364505

365506
maskImage[x, y] = pixel;

ImageSharpCompare/ImageSharpCompare.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
</ItemGroup>
4747

4848
<ItemGroup>
49-
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.2" />
49+
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
5050
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
51-
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.39.0.47922">
51+
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.40.0.48530">
5252
<PrivateAssets>all</PrivateAssets>
5353
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
5454
</PackageReference>

0 commit comments

Comments
 (0)