From dd81ba94196617455f0d794494b02b872daed857 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 07:11:21 +0000 Subject: [PATCH 1/7] Bump SkiaSharp.NativeAssets.Linux.NoDependencies from 3.119.2 to 3.119.4 --- updated-dependencies: - dependency-name: SkiaSharp.NativeAssets.Linux.NoDependencies dependency-version: 3.119.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- SkiaSharpCompare/SkiaSharpCompare.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkiaSharpCompare/SkiaSharpCompare.csproj b/SkiaSharpCompare/SkiaSharpCompare.csproj index bbe3881..4742dd6 100644 --- a/SkiaSharpCompare/SkiaSharpCompare.csproj +++ b/SkiaSharpCompare/SkiaSharpCompare.csproj @@ -46,7 +46,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 4e809a138dc3e4f99d4d3239f096308ebb9cf699 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:07:10 +0000 Subject: [PATCH 2/7] Bump SkiaSharp from 3.119.2 to 3.119.4 --- updated-dependencies: - dependency-name: SkiaSharp dependency-version: 3.119.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- SkiaSharpCompare/SkiaSharpCompare.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkiaSharpCompare/SkiaSharpCompare.csproj b/SkiaSharpCompare/SkiaSharpCompare.csproj index 4742dd6..47deb62 100644 --- a/SkiaSharpCompare/SkiaSharpCompare.csproj +++ b/SkiaSharpCompare/SkiaSharpCompare.csproj @@ -45,7 +45,7 @@ - + all From d28a1eeec3e5e80a477ce866d5434906f51c3dcb Mon Sep 17 00:00:00 2001 From: Stefan Seeland <168659+stesee@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:16:15 +0200 Subject: [PATCH 3/7] Implement CreateToleranceMaskFromDiff (issue #103) --- SkiaSharpCompare/SkiaSharpCompare.cs | 39 +++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/SkiaSharpCompare/SkiaSharpCompare.cs b/SkiaSharpCompare/SkiaSharpCompare.cs index cc16dd8..8a0c700 100644 --- a/SkiaSharpCompare/SkiaSharpCompare.cs +++ b/SkiaSharpCompare/SkiaSharpCompare.cs @@ -766,5 +766,42 @@ private static (SKBitmap, SKBitmap, SKBitmap) GrowToSameDimension(SKBitmap image return (grownActual, grownExpected, grownMask); } + + /// + /// Create a tolerance mask by expanding non-black regions in a diff mask. + /// Non-black pixels in diffMask will be grown by padding into broader white areas + /// to tolerate local differences (e.g., filenames, timestamps). + /// + public static SKBitmap CreateToleranceMaskFromDiff(SKBitmap diffMask, int padding = 3) + { + ArgumentNullException.ThrowIfNull(diffMask); + var w = diffMask.Width; + var h = diffMask.Height; + var mask = new SKBitmap(w, h, SKColorType.Rgba8888, SKAlphaType.Unpremul); + using var canvas = new SKCanvas(mask); + canvas.Clear(SKColors.Black); + + using var paint = new SKPaint { Color = SKColors.White, IsAntialias = false }; + + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++) + { + var col = diffMask.GetPixel(x, y); + if (col.Alpha > 16 && (col.Red > 16 || col.Green > 16 || col.Blue > 16)) + { + var left = Math.Max(0, x - padding); + var top = Math.Max(0, y - padding); + var right = Math.Min(w, x + padding + 1); + var bottom = Math.Min(h, y + padding + 1); + var rect = new SKRectI(left, top, right, bottom); + canvas.DrawRect(rect, paint); + } + } + } + + canvas.Flush(); + return mask; + } } -} \ No newline at end of file +} From 0faedbb2c88e0ec38bdfd5cb912f987d383883db Mon Sep 17 00:00:00 2001 From: Stefan Seeland <168659+stesee@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:32:23 +0200 Subject: [PATCH 4/7] Addressed #103 --- .editorconfig | 3 + .../SkiaSharpCompareCliTests.cs | 1 - SkiaSharpCompare.Cli/CliRunner.cs | 4 +- .../DirectoryCompareSummary.cs | 6 +- SkiaSharpCompare.Cli/Program.cs | 4 +- SkiaSharpCompare/ImageCompare.cs | 77 ++++++++++++------ SkiaSharpCompare/MetadataComparer.cs | 3 +- SkiaSharpCompare/MetadataExtractorAdapter.cs | 2 +- SkiaSharpCompare/SkiaSharpCompare.cs | 39 +-------- .../SkiaSharpCompareMetaData_PathTests.cs | 17 ++++ .../SkiaSharpCompareMetaData_SkBitmap.cs | 20 ++--- .../SkiaSharpCompareTestNunit.csproj | 8 +- .../SkiaSharpCompareTests.cs | 29 +++---- .../SkiaSharpStaticCompareTests.cs | 28 +++---- .../TestData/createToleranceMaskFromDiff.png | Bin 0 -> 1855 bytes SkiaSharpCompareTestNunit/TestFiles.cs | 1 + 16 files changed, 126 insertions(+), 116 deletions(-) create mode 100644 SkiaSharpCompareTestNunit/TestData/createToleranceMaskFromDiff.png diff --git a/.editorconfig b/.editorconfig index cf8404e..3ca6b4f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,9 @@ csharp_style_var_elsewhere = true:warning csharp_style_var_for_built_in_types = true:warning csharp_style_var_when_type_is_apparent = true:warning +# CA1822: Mark members as static +dotnet_diagnostic.CA1822.severity = suggestion + [*.{cs,vb}] tab_width=4 indent_size=4 diff --git a/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs index 0087b4a..84f03c1 100644 --- a/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs +++ b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs @@ -1,4 +1,3 @@ -using Codeuctivity.SkiaSharpCompare.Cli; using NUnit.Framework; using System; using System.IO; diff --git a/SkiaSharpCompare.Cli/CliRunner.cs b/SkiaSharpCompare.Cli/CliRunner.cs index fea20fe..716e15b 100644 --- a/SkiaSharpCompare.Cli/CliRunner.cs +++ b/SkiaSharpCompare.Cli/CliRunner.cs @@ -1,4 +1,6 @@ -namespace Codeuctivity.SkiaSharpCompare.Cli +using Codeuctivity.SkiaSharpCompare; + +namespace SkiaSharpCompare.Cli { /// /// Helper that exposes programmatic entry points for the console and tests. diff --git a/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs b/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs index d6d0f99..4cd2fd5 100644 --- a/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs +++ b/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs @@ -1,11 +1,13 @@ -namespace Codeuctivity.SkiaSharpCompare.Cli +using Codeuctivity.SkiaSharpCompare; + +namespace SkiaSharpCompare.Cli { /// /// Summary of comparing two directories. /// public sealed class DirectoryCompareSummary { - public Dictionary MatchedResults { get; init; } = new(); + public Dictionary MatchedResults { get; init; } = new(); public List OnlyInA { get; init; } = new(); public List OnlyInB { get; init; } = new(); public List UnsupportedFiles { get; init; } = new(); diff --git a/SkiaSharpCompare.Cli/Program.cs b/SkiaSharpCompare.Cli/Program.cs index 8cac708..ffad1d8 100644 --- a/SkiaSharpCompare.Cli/Program.cs +++ b/SkiaSharpCompare.Cli/Program.cs @@ -1,6 +1,6 @@ -using SkiaSharpCompare.Metadata; +using Codeuctivity.SkiaSharpCompare; -namespace Codeuctivity.SkiaSharpCompare.Cli +namespace SkiaSharpCompare.Cli { internal static class Program { diff --git a/SkiaSharpCompare/ImageCompare.cs b/SkiaSharpCompare/ImageCompare.cs index 4579787..646a703 100644 --- a/SkiaSharpCompare/ImageCompare.cs +++ b/SkiaSharpCompare/ImageCompare.cs @@ -11,48 +11,40 @@ namespace Codeuctivity.SkiaSharpCompare /// such as resizing, transparency handling, and pixel color shift tolerance. It supports multiple input types, /// including file paths, streams, and in-memory bitmaps. The class also provides methods to generate difference /// masks and check for image equality or size equality. - public class ImageCompare + /// + /// Initializes a new instance of the class with the specified options for resizing, + /// transparency handling, and color shift tolerance. + /// + /// Specifies how images should be resized before comparison. The default is . + /// Specifies how transparency should be handled during comparison. The default is . + /// Specifies the tolerance for color shifts in pixel values during comparison. A value of 0 means no + /// tolerance, and higher values allow for greater differences. The default is 0. + /// If true, compares image metadata (EXIF, etc.) in addition to pixel data. + public class ImageCompare(ResizeOption resizeOption = ResizeOption.DontResize, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel, int pixelColorShiftTolerance = 0, bool compareMetadata = false) { - /// - /// Initializes a new instance of the class with the specified options for resizing, - /// transparency handling, and color shift tolerance. - /// - /// Specifies how images should be resized before comparison. The default is . - /// Specifies how transparency should be handled during comparison. The default is . - /// Specifies the tolerance for color shifts in pixel values during comparison. A value of 0 means no - /// tolerance, and higher values allow for greater differences. The default is 0. - /// If true, compares image metadata (EXIF, etc.) in addition to pixel data. - public ImageCompare(ResizeOption resizeOption = ResizeOption.DontResize, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel, int pixelColorShiftTolerance = 0, bool compareMetadata = false) - { - ResizeOption = resizeOption; - TransparencyOptions = transparencyOptions; - PixelColorShiftTolerance = pixelColorShiftTolerance; - CompareMetadata = compareMetadata; - } - /// /// Gets the resize option that determines how an image should be resized. /// - public ResizeOption ResizeOption { get; } + public ResizeOption ResizeOption { get; } = resizeOption; /// /// Gets the transparency options that determine how transparency should be handled during image comparison. /// - public TransparencyOptions TransparencyOptions { get; } + public TransparencyOptions TransparencyOptions { get; } = transparencyOptions; /// /// Gets the tolerance level for pixel color shifts in image processing operations. /// /// This property is typically used to determine whether two pixels are considered /// similar in color during image comparison or analysis tasks. - public int PixelColorShiftTolerance { get; } + public int PixelColorShiftTolerance { get; } = pixelColorShiftTolerance; /// /// Gets a value indicating whether metadata should be included in the comparison operation. /// - public bool CompareMetadata { get; } + public bool CompareMetadata { get; } = compareMetadata; /// /// Calculates the difference between two images located at the specified file paths. @@ -303,5 +295,42 @@ public static bool ImagesHaveEqualSize(string pathImage1, string pathImage2) { return Compare.ImagesHaveEqualSize(pathImage1, pathImage2); } + + /// + /// Create a tolerance mask by expanding non-black regions in a diff mask. + /// Non-black pixels in diffMask will be grown by padding into broader white areas + /// to tolerate local differences (e.g., filenames, timestamps). + /// + public SKBitmap CreateToleranceMaskFromDiff(SKBitmap diffMask, int padding = 10) + { + ArgumentNullException.ThrowIfNull(diffMask); + var w = diffMask.Width; + var h = diffMask.Height; + var mask = new SKBitmap(w, h, SKColorType.Rgba8888, SKAlphaType.Unpremul); + using var canvas = new SKCanvas(mask); + canvas.Clear(SKColors.Black); + + using var paint = new SKPaint { Color = SKColors.White, IsAntialias = false }; + + for (var y = 0; y < h; y++) + { + for (var x = 0; x < w; x++) + { + var col = diffMask.GetPixel(x, y); + if (col.Alpha > 16 && (col.Red > 16 || col.Green > 16 || col.Blue > 16)) + { + var left = Math.Max(0, x - padding); + var top = Math.Max(0, y - padding); + var right = Math.Min(w, x + padding + 1); + var bottom = Math.Min(h, y + padding + 1); + var rect = new SKRectI(left, top, right, bottom); + canvas.DrawRect(rect, paint); + } + } + } + + canvas.Flush(); + return mask; + } } } \ No newline at end of file diff --git a/SkiaSharpCompare/MetadataComparer.cs b/SkiaSharpCompare/MetadataComparer.cs index c77e946..5869b5b 100644 --- a/SkiaSharpCompare/MetadataComparer.cs +++ b/SkiaSharpCompare/MetadataComparer.cs @@ -1,5 +1,4 @@ -using SkiaSharpCompare.Metadata; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/SkiaSharpCompare/MetadataExtractorAdapter.cs b/SkiaSharpCompare/MetadataExtractorAdapter.cs index 8fb10bf..6a9fb81 100644 --- a/SkiaSharpCompare/MetadataExtractorAdapter.cs +++ b/SkiaSharpCompare/MetadataExtractorAdapter.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace SkiaSharpCompare.Metadata +namespace Codeuctivity.SkiaSharpCompare { /// /// Provides static methods for extracting image metadata and returning it as a normalized dictionary of tag names diff --git a/SkiaSharpCompare/SkiaSharpCompare.cs b/SkiaSharpCompare/SkiaSharpCompare.cs index 8a0c700..cc16dd8 100644 --- a/SkiaSharpCompare/SkiaSharpCompare.cs +++ b/SkiaSharpCompare/SkiaSharpCompare.cs @@ -766,42 +766,5 @@ private static (SKBitmap, SKBitmap, SKBitmap) GrowToSameDimension(SKBitmap image return (grownActual, grownExpected, grownMask); } - - /// - /// Create a tolerance mask by expanding non-black regions in a diff mask. - /// Non-black pixels in diffMask will be grown by padding into broader white areas - /// to tolerate local differences (e.g., filenames, timestamps). - /// - public static SKBitmap CreateToleranceMaskFromDiff(SKBitmap diffMask, int padding = 3) - { - ArgumentNullException.ThrowIfNull(diffMask); - var w = diffMask.Width; - var h = diffMask.Height; - var mask = new SKBitmap(w, h, SKColorType.Rgba8888, SKAlphaType.Unpremul); - using var canvas = new SKCanvas(mask); - canvas.Clear(SKColors.Black); - - using var paint = new SKPaint { Color = SKColors.White, IsAntialias = false }; - - for (int y = 0; y < h; y++) - { - for (int x = 0; x < w; x++) - { - var col = diffMask.GetPixel(x, y); - if (col.Alpha > 16 && (col.Red > 16 || col.Green > 16 || col.Blue > 16)) - { - var left = Math.Max(0, x - padding); - var top = Math.Max(0, y - padding); - var right = Math.Min(w, x + padding + 1); - var bottom = Math.Min(h, y + padding + 1); - var rect = new SKRectI(left, top, right, bottom); - canvas.DrawRect(rect, paint); - } - } - } - - canvas.Flush(); - return mask; - } } -} +} \ No newline at end of file diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs index 8692ac4..ffeb658 100644 --- a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs +++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs @@ -1,5 +1,6 @@ using Codeuctivity.SkiaSharpCompare; using NUnit.Framework; +using SkiaSharp; using System; using System.Collections.Generic; using System.IO; @@ -82,6 +83,22 @@ public void CalcDiff_SamePixelComparedByMetadataShouldReturnCollectionOfMetadata Assert.That(actual.PixelErrorCount, Is.Zero); } + [Test] + public void CreateToleranceMaskFromDiff_CreatesWhiteRectangle() + { + var pic1 = Path.Combine(AppContext.BaseDirectory, TestFiles.png0Rgba32); + var pic2 = Path.Combine(AppContext.BaseDirectory, TestFiles.png1Rgba32); + var sut = new ImageCompare(); + + using var diffMask = sut.CalcDiffMaskImage(pic1, pic2); + using var tolFromBitmap = sut.CreateToleranceMaskFromDiff(diffMask); + + var expectedImage = SKBitmap.Decode(TestFiles.createToleranceMaskFromDiff); + + Assert.That(sut.ImagesAreEqual(tolFromBitmap, expectedImage), Is.True); + Assert.That(sut.CalcDiff(pic1, pic1, TestFiles.createToleranceMaskFromDiff).PixelErrorCount, Is.Zero); + } + private static string FormatMetadata(Dictionary? metadata) { if (metadata is null) diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs index 5a3386a..920f66e 100644 --- a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs +++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs @@ -25,13 +25,10 @@ public void ImagesAreEqual_SamePixelComparedByMetadataShouldThrows(string pic1Pa { var pic1 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, pic1Path)); var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, pic2Path)); - var sut = new ImageCompare(compareMetadata: true); + Action act = () => sut.ImagesAreEqual(pic1, pic2); - var ex = Assert.Throws(() => - { - sut.ImagesAreEqual(pic1, pic2); - }); + var ex = Assert.Throws(act); Assert.That(ex?.Message, Is.EqualTo("Metadata comparison is not implemented for SKBitmap inputs. https://github.com/mono/SkiaSharp/issues/1139 Use the overload with streams or filepath to get support for metadata comparison.")); } @@ -56,10 +53,9 @@ public void CalcDiff_SamePixelComparedByMetadataShouldReturnEmptyResult() var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata)); var sut = new ImageCompare(compareMetadata: true); - var ex = Assert.Throws(() => - { - sut.CalcDiff(pic1, pic2); - }); + Action act = () => sut.ImagesAreEqual(pic1, pic2); + + var ex = Assert.Throws(act); Assert.That(ex?.Message, Is.EqualTo("Metadata comparison is not implemented for SKBitmap inputs. https://github.com/mono/SkiaSharp/issues/1139 Use the overload with streams or filepath to get support for metadata comparison.")); } @@ -72,11 +68,9 @@ public void CalcDiff_SamePixelComparedByMetadataShouldReturnCollectionOfMetadata var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithGpsMetadata)); var sut = new ImageCompare(compareMetadata: true); + Action act = () => sut.ImagesAreEqual(pic1, pic2); - var ex = Assert.Throws(() => - { - sut.CalcDiff(pic1, pic2); - }); + var ex = Assert.Throws(act); Assert.That(ex?.Message, Is.EqualTo("Metadata comparison is not implemented for SKBitmap inputs. https://github.com/mono/SkiaSharp/issues/1139 Use the overload with streams or filepath to get support for metadata comparison.")); } diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj b/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj index 1a6ae10..c52bec6 100644 --- a/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj +++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj @@ -8,20 +8,20 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpCompareTests.cs index ff97f57..1c5c1ef 100644 --- a/SkiaSharpCompareTestNunit/SkiaSharpCompareTests.cs +++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareTests.cs @@ -158,8 +158,9 @@ public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1, var sut = new ImageCompare(); var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); + Action action = () => sut.CalcDiff(absolutePathPic1, absolutePathPic2); - var exception = Assert.Throws(() => sut.CalcDiff(absolutePathPic1, absolutePathPic2)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } @@ -191,11 +192,11 @@ public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pat Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage"); } - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, true)] - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.DontResize, true)] - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, true)] - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngWhite2x2px, 0, 0, 0, 0, ResizeOption.DontResize, false)] - public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, bool expectedOutcome) + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, ResizeOption.Resize, true)] + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, ResizeOption.DontResize, true)] + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, ResizeOption.Resize, true)] + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngWhite2x2px, ResizeOption.DontResize, false)] + public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, ResizeOption resizeOption, bool expectedOutcome) { var sut = new ImageCompare(resizeOption); var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); @@ -203,11 +204,8 @@ public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, int exp using var absolutePic1 = SKBitmap.Decode(absolutePathPic1); using var absolutePic2 = SKBitmap.Decode(absolutePathPic2); - - using (var maskImage = sut.CalcDiffMaskImage(absolutePic1, absolutePic2)) - { - Assert.That(ImageExtensions.IsImageEntirelyBlack(maskImage, TransparencyOptions.IgnoreAlphaChannel), Is.EqualTo(expectedOutcome)); - } + using var maskImage = sut.CalcDiffMaskImage(absolutePic1, absolutePic2); + Assert.That(ImageExtensions.IsImageEntirelyBlack(maskImage, TransparencyOptions.IgnoreAlphaChannel), Is.EqualTo(expectedOutcome)); } [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, null, TransparencyOptions.IgnoreAlphaChannel)] @@ -331,8 +329,9 @@ public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, stri using var pic1 = SKBitmap.Decode(absolutePathPic1); using var pic2 = SKBitmap.Decode(absolutePathPic2); using var maskPic = SKBitmap.Decode(differenceMaskPic); + Action action = () => sut.CalcDiff(pic1, pic2, maskPic); - var exception = Assert.Throws(() => sut.CalcDiff(pic1, pic2, maskPic)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } @@ -480,8 +479,9 @@ public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string var sut = new ImageCompare(ResizeOption.DontResize, transparencyOptions); var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); + Action action = () => sut.CalcDiff(absolutePathPic1, absolutePathPic2); - var exception = Assert.Throws(() => sut.CalcDiff(absolutePathPic1, absolutePathPic2)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } @@ -497,8 +497,9 @@ public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); var absolutePathPic3 = Path.Combine(AppContext.BaseDirectory, pathPic3); + Action action = () => sut.CalcDiff(absolutePathPic1, absolutePathPic2, absolutePathPic3); - var exception = Assert.Throws(() => sut.CalcDiff(absolutePathPic1, absolutePathPic2, absolutePathPic3)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } diff --git a/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs index 9c29f4e..ded1102 100644 --- a/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs +++ b/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs @@ -148,9 +148,9 @@ public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1, { var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); + Action action = () => Compare.CalcDiff(absolutePathPic1, absolutePathPic2, ResizeOption.DontResize); - var exception = Assert.Throws( - () => Compare.CalcDiff(absolutePathPic1, absolutePathPic2, ResizeOption.DontResize)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } @@ -215,21 +215,18 @@ private static void SaveAsPng(SKBitmap maskImage, FileStream fileStreamDifferenc encodedData.SaveTo(fileStreamDifferenceMask); } - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize)] - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.DontResize)] - [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)] - public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption) + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, ResizeOption.Resize)] + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, ResizeOption.DontResize)] + [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, ResizeOption.Resize)] + public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, ResizeOption resizeOption) { var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); using var absolutePic1 = SKBitmap.Decode(absolutePathPic1); using var absolutePic2 = SKBitmap.Decode(absolutePathPic2); - - using (var maskImage = Compare.CalcDiffMaskImage(absolutePic1, absolutePic2, resizeOption)) - { - Assert.That(ImageExtensions.IsImageEntirelyBlack(maskImage, TransparencyOptions.IgnoreAlphaChannel)); - } + using var maskImage = Compare.CalcDiffMaskImage(absolutePic1, absolutePic2, resizeOption); + Assert.That(ImageExtensions.IsImageEntirelyBlack(maskImage, TransparencyOptions.IgnoreAlphaChannel)); } [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)] @@ -296,8 +293,9 @@ public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, stri using var pic1 = SKBitmap.Decode(absolutePathPic1); using var pic2 = SKBitmap.Decode(absolutePathPic2); using var maskPic = SKBitmap.Decode(differenceMaskPic); + Action action = () => Compare.CalcDiff(pic1, pic2, maskPic, ResizeOption.Resize); - var exception = Assert.Throws(() => Compare.CalcDiff(pic1, pic2, maskPic, ResizeOption.DontResize)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } @@ -454,8 +452,9 @@ public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string { var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); + Action action = () => Compare.CalcDiff(absolutePathPic1, absolutePathPic2); - var exception = Assert.Throws(() => Compare.CalcDiff(absolutePathPic1, absolutePathPic2)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } @@ -468,8 +467,9 @@ public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1); var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2); var absolutePathPic3 = Path.Combine(AppContext.BaseDirectory, pathPic3); + Action action = () => Compare.CalcDiff(absolutePathPic1, absolutePathPic2, absolutePathPic3); - var exception = Assert.Throws(() => Compare.CalcDiff(absolutePathPic1, absolutePathPic2, absolutePathPic3)); + var exception = Assert.Throws(action); Assert.That(exception?.Message, Is.EqualTo("Size of images differ.")); } diff --git a/SkiaSharpCompareTestNunit/TestData/createToleranceMaskFromDiff.png b/SkiaSharpCompareTestNunit/TestData/createToleranceMaskFromDiff.png new file mode 100644 index 0000000000000000000000000000000000000000..24ab8f471cf1373a1b1581ca3725d8853871e610 GIT binary patch literal 1855 zcmeAS@N?(olHy`uVBq!ia0y~yU~~fFZyanu5!P?5|A7=sv6E*A2N2Y7q;xPauzmA% zaSW-L^Y-q+tX2a7hl@+T{I9>cZr7UiPhA)7eV)TQ^J=QfisGI^o`wzmcbOU9sI@rE z6JV-z;&{TTI6-}IalY@YX85uCvBk9e#pibZnP=19D{w;CNx`3^(MFNwQww&^d#U1A zUEix7=H*c88S~>3|IRTlxrx_0><)Qf{GH*z|8kk?{r_#A+w9eAIgnb${$aa~6!Y{7 zFP3%zrtpd&5ViWQVbl6FA+VoP-|gV7v!3k>wr<*v&t^Zm1ehf4k4B-{zuordkqQpQ z1_358L8Yksu+8%MJHdNOus}=s^Mykn#?dMKKKb$HpWqNrn7KQzb^S9Tr-YTekA3I? zryZT|Th<0}GHB=;4pxQ9byQ|7hrphR%q~Kl>OM|LMN@ U=WKBXSR*ocy85}Sb4q9e06`vH!~g&Q literal 0 HcmV?d00001 diff --git a/SkiaSharpCompareTestNunit/TestFiles.cs b/SkiaSharpCompareTestNunit/TestFiles.cs index d22b333..b6b05dc 100644 --- a/SkiaSharpCompareTestNunit/TestFiles.cs +++ b/SkiaSharpCompareTestNunit/TestFiles.cs @@ -20,5 +20,6 @@ internal static class TestFiles public const string imageWithoutGpsMetadata = "./../../../TestData/imageWithoutGpsMetadata.jpg"; public const string imageWithGpsMetadata = "./../../../TestData/imageWithGpsMetadata.jpg"; + public const string createToleranceMaskFromDiff = "./../../../TestData/createToleranceMaskFromDiff.png"; } } \ No newline at end of file From 880c79a8117d0c8a2247a36a8514f55f2451dbb2 Mon Sep 17 00:00:00 2001 From: Stefan Seeland <168659+stesee@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:42:52 +0200 Subject: [PATCH 5/7] Update SkiaSharpStaticCompareTests.cs --- SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs index ded1102..94955c5 100644 --- a/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs +++ b/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs @@ -293,7 +293,7 @@ public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, stri using var pic1 = SKBitmap.Decode(absolutePathPic1); using var pic2 = SKBitmap.Decode(absolutePathPic2); using var maskPic = SKBitmap.Decode(differenceMaskPic); - Action action = () => Compare.CalcDiff(pic1, pic2, maskPic, ResizeOption.Resize); + Action action = () => Compare.CalcDiff(pic1, pic2, maskPic, ResizeOption.DontResize); var exception = Assert.Throws(action); From da8eb0650cb191dbb135ebd7241e5085cd1bc747 Mon Sep 17 00:00:00 2001 From: Stefan Seeland <168659+stesee@users.noreply.github.com> Date: Tue, 9 Jun 2026 03:31:47 +0200 Subject: [PATCH 6/7] Update SkiaSharp and its native assets version --- SkiaSharpCompare/SkiaSharpCompare.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SkiaSharpCompare/SkiaSharpCompare.csproj b/SkiaSharpCompare/SkiaSharpCompare.csproj index 4fddce8..c54b4c1 100644 --- a/SkiaSharpCompare/SkiaSharpCompare.csproj +++ b/SkiaSharpCompare/SkiaSharpCompare.csproj @@ -45,8 +45,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From 90cdde170ce6bece658bb5dbcf71286725d0a98c Mon Sep 17 00:00:00 2001 From: Stefan Seeland <168659+stesee@users.noreply.github.com> Date: Tue, 9 Jun 2026 03:43:28 +0200 Subject: [PATCH 7/7] Fix duplicate equals sign in SkiaSharp version --- SkiaSharpCompare/SkiaSharpCompare.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkiaSharpCompare/SkiaSharpCompare.csproj b/SkiaSharpCompare/SkiaSharpCompare.csproj index c54b4c1..04c5d05 100644 --- a/SkiaSharpCompare/SkiaSharpCompare.csproj +++ b/SkiaSharpCompare/SkiaSharpCompare.csproj @@ -45,7 +45,7 @@ - + all