diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml
index 5630596..9e24d20 100644
--- a/.github/workflows/cla.yml
+++ b/.github/workflows/cla.yml
@@ -21,7 +21,7 @@ jobs:
path-to-document: 'https://github.com/Codeuctivity/SkiaSharp.Compare/blob/main/cla.md' # e.g. a CLA or a DCO document
# branch should not be protected
branch: 'cla'
- allowlist: dependabot[bot],stesee,github-copilot[bot]
+ allowlist: dependabot[bot],stesee,github-actions[bot],github-copilot[bot],copilot[bot]
#below are the optional inputs - If the optional inputs are not given, then default values will be taken
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index eb1e77c..b70ff7c 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -1,6 +1,6 @@
name: .NET build and test
env:
- CURRENT_VERSION: 3.1.${{ github.run_number }}
+ CURRENT_VERSION: 3.2.${{ github.run_number }}
LAST_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
on:
@@ -27,6 +27,30 @@ jobs:
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
+
+ - name: Publish SkiaSharpCompare.Cli (Linux)
+ if: runner.os == 'Linux'
+ run: |
+ dotnet publish SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -o ./artifacts/cli/linux-x64
+
+ - name: Publish SkiaSharpCompare.Cli (macOS)
+ if: runner.os == 'macOS'
+ run: |
+ dotnet publish SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -o ./artifacts/cli/osx-x64
+
+ - name: Publish SkiaSharpCompare.Cli (Windows)
+ if: runner.os == 'Windows'
+ shell: powershell
+ run: |
+ dotnet publish SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o ./artifacts/cli/win-x64
+ dotnet publish SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj -c Release -r win-arm64 --self-contained true -p:PublishSingleFile=true -o ./artifacts/cli/win-arm64
+
+ - name: Upload CLI artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: cli-artifacts-${{ matrix.os }}
+ path: ./artifacts/cli
+
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
@@ -47,6 +71,10 @@ jobs:
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
+ - name: Download CLI artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: ./artifacts_download
- name: NugetPush
env:
NUGET_TOKEN_EXISTS: ${{ secrets.NUGET_TOKEN }}
@@ -54,11 +82,14 @@ jobs:
run: |
dotnet nuget push ./SkiaSharpCompare/bin/Release/*.nupkg --skip-duplicate --api-key ${{secrets.NUGET_TOKEN}} --source https://api.nuget.org/v3/index.json
- name: Github release
+ shell: bash
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
if: env.GITHUB_TOKEN != ''
run: |
- gh release create ${{env.CURRENT_VERSION}} ./SkiaSharpCompare/bin/Release/*.*nupkg --generate-notes
+ # Attach all downloaded CLI artifacts regardless of OS
+ zip -r cli-artifacts.zip ./artifacts_download
+ gh release create ${{env.CURRENT_VERSION}} ./SkiaSharpCompare/bin/Release/*.*nupkg cli-artifacts.zip --generate-notes
deployTest:
if: ${{ !startsWith(github.ref, 'refs/heads/release') }}
@@ -77,6 +108,10 @@ jobs:
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
+ - name: Download CLI artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: ./artifacts_download
- name: NugetPush
env:
NUGET_TOKEN_EXISTS: ${{ secrets.NUGET_TEST_TOKEN }}
@@ -90,4 +125,5 @@ jobs:
GITHUB_TOKEN: ${{ github.TOKEN }}
if: env.GITHUB_TOKEN != ''
run: |
- gh release create ${{env.CURRENT_VERSION}} ./SkiaSharpCompare/bin/Release/*.*nupkg --prerelease --generate-notes
+ zip -r cli-artifacts.zip ./artifacts_download
+ gh release create ${{env.CURRENT_VERSION}} ./SkiaSharpCompare/bin/Release/*.*nupkg cli-artifacts.zip --prerelease --generate-notes
diff --git a/SkiaSharpCompare.Cli.Tests/SkiaSharpCompare.Cli.Tests.csproj b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompare.Cli.Tests.csproj
new file mode 100644
index 0000000..0414ea4
--- /dev/null
+++ b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompare.Cli.Tests.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net10.0
+ false
+ 12
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliIntegrationTests.cs b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliIntegrationTests.cs
new file mode 100644
index 0000000..c78cf6c
--- /dev/null
+++ b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliIntegrationTests.cs
@@ -0,0 +1,64 @@
+using NUnit.Framework;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace SkiaSharpCompare.Cli.Tests
+{
+ public class SkiaSharpCompareCliIntegrationTests
+ {
+ private const int ProcessTimeoutMs = 30_000;
+
+ [Test]
+ public async Task SkiaSharpCompareCli_ShouldExitSuccessfully()
+ {
+ // Static precompiled CLI project directory (relative to test assembly output).
+ var cliProjectDir = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "SkiaSharpCompare.Cli"));
+ Assert.That(Directory.Exists(cliProjectDir), Is.True, $"Could not locate CLI project directory at '{cliProjectDir}'. Ensure the solution layout is unchanged and the path is valid.");
+
+ // Find a JPG file in the repository to pass to the CLI.
+ var jpgFile = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "SkiaSharpCompareTestNunit", "TestData", "imageWithGpsMetadata.jpg"));
+ Assert.That(jpgFile, Is.Not.Null, "Could not locate any .jpg file in the repository to use for the integration test.");
+
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = "dotnet",
+ Arguments = $"run -- \"{jpgFile}\" --meta",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = false,
+ WorkingDirectory = cliProjectDir
+ };
+
+ using var process = new Process { StartInfo = startInfo };
+
+ process.Start();
+
+ var stdOutTask = process.StandardOutput.ReadToEndAsync();
+ var stdErrTask = process.StandardError.ReadToEndAsync();
+
+ var exited = await Task.Run(() => process.WaitForExit(ProcessTimeoutMs));
+ if (!exited)
+ {
+ try
+ {
+ process.Kill(entireProcessTree: true);
+ }
+ catch
+ {
+ // Best effort
+ }
+
+ Assert.Fail($"Process did not exit within {ProcessTimeoutMs} ms. StdOut:{Environment.NewLine}{await stdOutTask}{Environment.NewLine}StdErr:{Environment.NewLine}{await stdErrTask}");
+ }
+
+ var stdout = await stdOutTask;
+ var stderr = await stdErrTask;
+
+ Assert.That(process.ExitCode, Is.EqualTo(0), $"Process exited with non-zero exit code {process.ExitCode}.{Environment.NewLine}StdOut:{Environment.NewLine}{stdout}{Environment.NewLine}StdErr:{Environment.NewLine}{stderr}");
+ Assert.That(stdout, Does.Contain("GPS:GPS Altitude: 201"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs
new file mode 100644
index 0000000..0087b4a
--- /dev/null
+++ b/SkiaSharpCompare.Cli.Tests/SkiaSharpCompareCliTests.cs
@@ -0,0 +1,75 @@
+using Codeuctivity.SkiaSharpCompare.Cli;
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace SkiaSharpCompare.Cli.Tests
+{
+ [TestFixture]
+ public class SkiaSharpCompareCliTests
+ {
+ [Test]
+ public void CompareFiles_NonImageFiles_AreReportedUnsupported()
+ {
+ var dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
+ Directory.CreateDirectory(dir);
+
+ try
+ {
+ var a = Path.Combine(dir, "a.txt");
+ var b = Path.Combine(dir, "b.txt");
+
+ File.WriteAllText(a, "not an image");
+ File.WriteAllText(b, "not an image");
+
+ var info = CliRunner.CompareFiles(a, b);
+ Assert.That(info.Unsupported, Is.True);
+ Assert.That(info.Result, Is.Null);
+ Assert.That(info.ErrorMessage, Is.Not.Null.And.Not.Empty);
+ }
+ finally
+ {
+ Directory.Delete(dir, true);
+ }
+ }
+
+ [Test]
+ public void CompareDirectories_MatchesMissingAndUnsupported()
+ {
+ var root = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
+ var dirA = Path.Combine(root, "A");
+ var dirB = Path.Combine(root, "B");
+ Directory.CreateDirectory(dirA);
+ Directory.CreateDirectory(dirB);
+
+ try
+ {
+ // file only in A
+ var onlyA = Path.Combine(dirA, "onlyA.txt");
+ File.WriteAllText(onlyA, "not image");
+
+ // file only in B
+ var onlyB = Path.Combine(dirB, "onlyB.txt");
+ File.WriteAllText(onlyB, "not image");
+
+ // common file (but not a valid image)
+ var commonA = Path.Combine(dirA, "common.jpg");
+ var commonB = Path.Combine(dirB, "common.jpg");
+ File.WriteAllText(commonA, "not an image");
+ File.WriteAllText(commonB, "not an image");
+
+ var summary = CliRunner.CompareDirectories(dirA, dirB);
+
+ Assert.That(summary.OnlyInA, Has.Member("onlyA.txt"));
+ Assert.That(summary.OnlyInB, Has.Member("onlyB.txt"));
+ Assert.That(summary.MatchedResults.Keys, Has.Member("common.jpg"));
+ Assert.That(summary.MatchedResults["common.jpg"], Is.Null);
+ Assert.That(summary.UnsupportedFiles, Has.Member("common.jpg"));
+ }
+ finally
+ {
+ Directory.Delete(root, true);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare.Cli/CliRunner.cs b/SkiaSharpCompare.Cli/CliRunner.cs
new file mode 100644
index 0000000..fea20fe
--- /dev/null
+++ b/SkiaSharpCompare.Cli/CliRunner.cs
@@ -0,0 +1,247 @@
+namespace Codeuctivity.SkiaSharpCompare.Cli
+{
+ ///
+ /// Helper that exposes programmatic entry points for the console and tests.
+ ///
+ public static class CliRunner
+ {
+ ///
+ /// Result wrapper for a single file comparison.
+ ///
+ public sealed class FileCompareInfo
+ {
+ public ICompareResult? Result { get; init; }
+ public bool Unsupported { get; init; }
+ public string? ErrorMessage { get; init; }
+ }
+
+ ///
+ /// Compare two image files. If an image cannot be loaded or compared,
+ /// will be true and will be null.
+ ///
+ public static FileCompareInfo CompareFiles(string pathA, string pathB, bool compareMetadata = true)
+ {
+ if (string.IsNullOrWhiteSpace(pathA))
+ {
+ throw new ArgumentException("PathA is required", nameof(pathA));
+ }
+
+ if (string.IsNullOrWhiteSpace(pathB))
+ {
+ throw new ArgumentException("PathB is required", nameof(pathB));
+ }
+
+ var absoluteA = Path.GetFullPath(pathA);
+ var absoluteB = Path.GetFullPath(pathB);
+
+ var comparer = new ImageCompare(compareMetadata: compareMetadata);
+
+ try
+ {
+ var result = comparer.CalcDiff(absoluteA, absoluteB);
+ return new FileCompareInfo
+ {
+ Result = result,
+ Unsupported = false,
+ ErrorMessage = null
+ };
+ }
+ catch (Exception ex)
+ {
+ return new FileCompareInfo
+ {
+ Result = null,
+ Unsupported = true,
+ ErrorMessage = ex.Message
+ };
+ }
+ }
+
+ ///
+ /// Compare two directories. Matches files by filename. Returns compare results for matched names,
+ /// lists of files existing only in one directory and a list of files which failed to be compared (unsupported).
+ ///
+ public static DirectoryCompareSummary CompareDirectories(string directoryA, string directoryB, bool compareMetadata = true)
+ {
+ if (string.IsNullOrWhiteSpace(directoryA))
+ {
+ throw new ArgumentException("directoryA is required", nameof(directoryA));
+ }
+
+ if (string.IsNullOrWhiteSpace(directoryB))
+ {
+ throw new ArgumentException("directoryB is required", nameof(directoryB));
+ }
+
+ var dirA = Path.GetFullPath(directoryA);
+ var dirB = Path.GetFullPath(directoryB);
+
+ if (!Directory.Exists(dirA))
+ {
+ throw new DirectoryNotFoundException(dirA);
+ }
+
+ if (!Directory.Exists(dirB))
+ {
+ throw new DirectoryNotFoundException(dirB);
+ }
+
+ var filesA = Directory.GetFiles(dirA).Select(Path.GetFileName).Where(n => n != null).Cast().ToHashSet(StringComparer.OrdinalIgnoreCase);
+ var filesB = Directory.GetFiles(dirB).Select(Path.GetFileName).Where(n => n != null).Cast().ToHashSet(StringComparer.OrdinalIgnoreCase);
+
+ var onlyInA = filesA.Except(filesB, StringComparer.OrdinalIgnoreCase).OrderBy(n => n).ToList();
+ var onlyInB = filesB.Except(filesA, StringComparer.OrdinalIgnoreCase).OrderBy(n => n).ToList();
+ var matched = filesA.Intersect(filesB, StringComparer.OrdinalIgnoreCase).OrderBy(n => n).ToList();
+
+ var matchedResults = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ var unsupported = new List();
+
+ foreach (var fileName in matched)
+ {
+ var pathA = Path.Combine(dirA, fileName);
+ var pathB = Path.Combine(dirB, fileName);
+
+ var info = CompareFiles(pathA, pathB, compareMetadata: compareMetadata);
+ if (info.Unsupported)
+ {
+ matchedResults[fileName] = null;
+ unsupported.Add(fileName);
+ }
+ else
+ {
+ matchedResults[fileName] = info.Result;
+ }
+ }
+
+ return new DirectoryCompareSummary
+ {
+ MatchedResults = matchedResults,
+ OnlyInA = onlyInA,
+ OnlyInB = onlyInB,
+ UnsupportedFiles = unsupported
+ };
+ }
+
+ ///
+ /// Print a file comparison result to the provided text writer.
+ ///
+ public static void PrintCompareResult(FileCompareInfo info, TextWriter writer, string? nameA = null, string? nameB = null)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ nameA ??= "A";
+ nameB ??= "B";
+
+ writer.WriteLine($"Comparing: {nameA} <> {nameB}");
+
+ if (info.Unsupported)
+ {
+ writer.WriteLine($" Unsupported or failed to compare: {info.ErrorMessage}");
+ return;
+ }
+
+ var result = info.Result!;
+ writer.WriteLine($" PixelErrorCount: {result.PixelErrorCount}");
+ writer.WriteLine($" PixelErrorPercentage: {result.PixelErrorPercentage:F4}");
+ writer.WriteLine($" AbsoluteError: {result.AbsoluteError}");
+ writer.WriteLine($" MeanError: {result.MeanError:F4}");
+
+ if (result.MetadataDifferences is null)
+ {
+ writer.WriteLine(" Metadata comparison disabled (null).");
+ }
+ else if (result.MetadataDifferences.Count == 0)
+ {
+ writer.WriteLine(" Metadata: no differences.");
+ }
+ else
+ {
+ writer.WriteLine(" Metadata differences:");
+ foreach (var kvp in result.MetadataDifferences)
+ {
+ writer.WriteLine($" {kvp.Key}: (A: {kvp.Value.ValueA ?? string.Empty}, B: {kvp.Value.ValueB ?? string.Empty})");
+ }
+ }
+ }
+
+ ///
+ /// Print directory compare summary to the writer.
+ ///
+ public static void PrintDirectorySummary(DirectoryCompareSummary summary, TextWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteLine("Directory comparison summary:");
+ writer.WriteLine();
+
+ writer.WriteLine("Matched files:");
+ if (summary.MatchedResults.Count == 0)
+ {
+ writer.WriteLine(" (none)");
+ }
+ else
+ {
+ foreach (var kvp in summary.MatchedResults.OrderBy(k => k.Key, StringComparer.OrdinalIgnoreCase))
+ {
+ writer.WriteLine($" {kvp.Key}:");
+ if (kvp.Value is null)
+ {
+ writer.WriteLine(" Unsupported or failed to compare");
+ }
+ else
+ {
+ writer.WriteLine($" PixelErrorCount: {kvp.Value.PixelErrorCount}, PixelErrorPercentage: {kvp.Value.PixelErrorPercentage:F4}");
+ }
+ }
+ }
+
+ writer.WriteLine();
+ writer.WriteLine("Only in A:");
+ if (summary.OnlyInA.Count == 0)
+ {
+ writer.WriteLine(" (none)");
+ }
+ else
+ {
+ foreach (var n in summary.OnlyInA)
+ {
+ writer.WriteLine($" {n}");
+ }
+ }
+
+ writer.WriteLine();
+ writer.WriteLine("Only in B:");
+ if (summary.OnlyInB.Count == 0)
+ {
+ writer.WriteLine(" (none)");
+ }
+ else
+ {
+ foreach (var n in summary.OnlyInB)
+ {
+ writer.WriteLine($" {n}");
+ }
+ }
+
+ writer.WriteLine();
+ writer.WriteLine("Unsupported files:");
+ if (summary.UnsupportedFiles.Count == 0)
+ {
+ writer.WriteLine(" (none)");
+ }
+ else
+ {
+ foreach (var n in summary.UnsupportedFiles)
+ {
+ writer.WriteLine($" {n}");
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs b/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs
new file mode 100644
index 0000000..d6d0f99
--- /dev/null
+++ b/SkiaSharpCompare.Cli/DirectoryCompareSummary.cs
@@ -0,0 +1,13 @@
+namespace Codeuctivity.SkiaSharpCompare.Cli
+{
+ ///
+ /// Summary of comparing two directories.
+ ///
+ public sealed class DirectoryCompareSummary
+ {
+ public Dictionary MatchedResults { get; init; } = new();
+ public List OnlyInA { get; init; } = new();
+ public List OnlyInB { get; init; } = new();
+ public List UnsupportedFiles { get; init; } = new();
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare.Cli/Program.cs b/SkiaSharpCompare.Cli/Program.cs
new file mode 100644
index 0000000..8cac708
--- /dev/null
+++ b/SkiaSharpCompare.Cli/Program.cs
@@ -0,0 +1,81 @@
+using SkiaSharpCompare.Metadata;
+
+namespace Codeuctivity.SkiaSharpCompare.Cli
+{
+ internal static class Program
+ {
+ private static int Main(string[] args)
+ {
+ if (args is null || args.Length < 1)
+ {
+ Console.WriteLine("Usage:");
+ Console.WriteLine(" dotnet run -- ");
+ Console.WriteLine(" dotnet run -- --dir");
+ Console.WriteLine(" dotnet run -- --meta # show metadata for a file");
+ return 2;
+ }
+
+ try
+ {
+ // If user requested metadata display
+ if (Array.IndexOf(args, "--meta") >= 0)
+ {
+ var fileArg = args[0];
+ var absolute = Path.GetFullPath(fileArg);
+ if (!File.Exists(absolute))
+ {
+ Console.Error.WriteLine($"File not found: {absolute}");
+ return 4;
+ }
+
+ try
+ {
+ var meta = MetadataExtractorAdapter.Extract(absolute);
+ Console.WriteLine($"Metadata for: {absolute}");
+ if (meta.Count == 0)
+ {
+ Console.WriteLine(" (no metadata found)");
+ }
+ else
+ {
+ foreach (var kv in meta.OrderBy(k => k.Key))
+ {
+ Console.WriteLine($" {kv.Key}: {kv.Value}");
+ }
+ }
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine($"Failed to extract metadata: {ex.Message}");
+ return 5;
+ }
+ }
+
+ if (args.Length >= 3 && args[2] == "--dir")
+ {
+ var summary = CliRunner.CompareDirectories(args[0], args[1]);
+ CliRunner.PrintDirectorySummary(summary, Console.Out);
+ }
+ else if (args.Length >= 2)
+ {
+ var resultInfo = CliRunner.CompareFiles(args[0], args[1], compareMetadata: true);
+ CliRunner.PrintCompareResult(resultInfo, Console.Out, Path.GetFileName(args[0]), Path.GetFileName(args[1]));
+ }
+ else
+ {
+ Console.WriteLine("Insufficient arguments. See usage.");
+ return 2;
+ }
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine($"Fatal error: {ex.Message}");
+ return 3;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj b/SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj
new file mode 100644
index 0000000..70af7c5
--- /dev/null
+++ b/SkiaSharpCompare.Cli/SkiaSharpCompare.Cli.csproj
@@ -0,0 +1,15 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ 12
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SkiaSharpCompare.sln b/SkiaSharpCompare.sln
index 1524ac7..55a8a70 100644
--- a/SkiaSharpCompare.sln
+++ b/SkiaSharpCompare.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
+# Visual Studio Version 18
+VisualStudioVersion = 18.0.11222.15 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A1B6F6C3-ECBE-471C-AE18-199DEF5982C3}"
ProjectSection(SolutionItems) = preProject
@@ -17,6 +17,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharpCompare", "SkiaSha
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharpCompareTestNunit", "SkiaSharpCompareTestNunit\SkiaSharpCompareTestNunit.csproj", "{9CFA9A6F-92FC-40E3-BB85-4C8F95EFC8C7}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkiaSharpCompare.Cli", "SkiaSharpCompare.Cli\SkiaSharpCompare.Cli.csproj", "{296B4D6C-C8F6-81DE-9B65-D4CE48783B52}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkiaSharpCompare.Cli.Tests", "SkiaSharpCompare.Cli.Tests\SkiaSharpCompare.Cli.Tests.csproj", "{059AD3EF-A494-850F-6457-E5C4D706CC94}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -31,6 +35,14 @@ Global
{9CFA9A6F-92FC-40E3-BB85-4C8F95EFC8C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CFA9A6F-92FC-40E3-BB85-4C8F95EFC8C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CFA9A6F-92FC-40E3-BB85-4C8F95EFC8C7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {296B4D6C-C8F6-81DE-9B65-D4CE48783B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {296B4D6C-C8F6-81DE-9B65-D4CE48783B52}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {296B4D6C-C8F6-81DE-9B65-D4CE48783B52}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {296B4D6C-C8F6-81DE-9B65-D4CE48783B52}.Release|Any CPU.Build.0 = Release|Any CPU
+ {059AD3EF-A494-850F-6457-E5C4D706CC94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {059AD3EF-A494-850F-6457-E5C4D706CC94}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {059AD3EF-A494-850F-6457-E5C4D706CC94}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {059AD3EF-A494-850F-6457-E5C4D706CC94}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/SkiaSharpCompare/CompareResult.cs b/SkiaSharpCompare/CompareResult.cs
index 30aac45..bed79df 100644
--- a/SkiaSharpCompare/CompareResult.cs
+++ b/SkiaSharpCompare/CompareResult.cs
@@ -1,45 +1,48 @@
+using System.Collections.Generic;
+
namespace Codeuctivity.SkiaSharpCompare
{
///
/// Dto - outcome of compared images
///
- public class CompareResult : ICompareResult
+ ///
+ /// ctor for CompareResult
+ ///
+ /// Mean error
+ /// Absolute error
+ /// Number of pixels that differ between images
+ /// Percentage of pixels that differ between images
+ /// Metadata that differ between images
+ public class CompareResult(int absoluteError, double meanError, int pixelErrorCount, double pixelErrorPercentage, Dictionary? metadataDifference = null) : ICompareResult
{
///
/// Mean pixel error of absolute pixel error
///
/// 0-765
- public double MeanError { get; }
+ public double MeanError { get; } = meanError;
///
/// Absolute pixel error, counts each color channel on every pixel the delta
///
- public int AbsoluteError { get; }
+ public int AbsoluteError { get; } = absoluteError;
///
/// Number of pixels that differ between images
///
- public int PixelErrorCount { get; }
+ public int PixelErrorCount { get; } = pixelErrorCount;
///
/// Percentage of pixels that differ between images
///
/// 0-100.0
- public double PixelErrorPercentage { get; }
+ public double PixelErrorPercentage { get; } = pixelErrorPercentage;
///
- /// ctor for CompareResult
+ /// Gets a collection of metadata keys and their differing values between two sources.
///
- /// Mean error
- /// Absolute error
- /// Number of pixels that differ between images
- /// Percentage of pixels that differ between images
- public CompareResult(int absoluteError, double meanError, int pixelErrorCount, double pixelErrorPercentage)
- {
- MeanError = meanError;
- AbsoluteError = absoluteError;
- PixelErrorCount = pixelErrorCount;
- PixelErrorPercentage = pixelErrorPercentage;
- }
+ /// Each entry in the dictionary represents a metadata key for which the values differ.
+ /// The tuple contains the value from the first source and the value from the second source, respectively. If a
+ /// value is null, the key may be missing from that source.
+ public Dictionary? MetadataDifferences { get; } = metadataDifference;
}
}
\ No newline at end of file
diff --git a/SkiaSharpCompare/CompareResultWithMetadata.cs b/SkiaSharpCompare/CompareResultWithMetadata.cs
new file mode 100644
index 0000000..abb087e
--- /dev/null
+++ b/SkiaSharpCompare/CompareResultWithMetadata.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace Codeuctivity.SkiaSharpCompare
+{
+ internal class CompareResultWithMetadata(ICompareResult compareResult, Dictionary? metadataDiff) : ICompareResult
+ {
+ public double MeanError { get; } = compareResult.MeanError;
+ public int AbsoluteError { get; } = compareResult.AbsoluteError;
+ public int PixelErrorCount { get; } = compareResult.PixelErrorCount;
+ public double PixelErrorPercentage { get; } = compareResult.PixelErrorPercentage;
+ public Dictionary? MetadataDifferences { get; } = metadataDiff;
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare/ICompareResult.cs b/SkiaSharpCompare/ICompareResult.cs
index 9d737ca..8099b25 100644
--- a/SkiaSharpCompare/ICompareResult.cs
+++ b/SkiaSharpCompare/ICompareResult.cs
@@ -1,4 +1,6 @@
-namespace Codeuctivity.SkiaSharpCompare
+using System.Collections.Generic;
+
+namespace Codeuctivity.SkiaSharpCompare
{
///
/// Dto - of compared images
@@ -24,5 +26,13 @@ public interface ICompareResult
/// Percentage of pixels that differ between images
///
double PixelErrorPercentage { get; }
+
+ ///
+ /// Gets a collection of metadata keys and their differing values between two sources.
+ ///
+ /// Each entry in the dictionary represents a metadata key for which the values differ
+ /// between the two compared sources. The tuple contains the value from the first source and the value from the
+ /// second source. If there are no differences or metadata is unavailable, the property returns null.
+ Dictionary? MetadataDifferences { get; }
}
}
\ No newline at end of file
diff --git a/SkiaSharpCompare/ImageCompare.cs b/SkiaSharpCompare/ImageCompare.cs
index 4696815..4579787 100644
--- a/SkiaSharpCompare/ImageCompare.cs
+++ b/SkiaSharpCompare/ImageCompare.cs
@@ -1,4 +1,5 @@
using SkiaSharp;
+using System;
using System.IO;
namespace Codeuctivity.SkiaSharpCompare
@@ -22,11 +23,13 @@ public class ImageCompare
/// cref="TransparencyOptions.CompareAlphaChannel"/>.
/// 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.
- public ImageCompare(ResizeOption resizeOption = ResizeOption.DontResize, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel, int pixelColorShiftTolerance = 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;
}
///
@@ -46,121 +49,203 @@ public ImageCompare(ResizeOption resizeOption = ResizeOption.DontResize, Transpa
/// similar in color during image comparison or analysis tasks.
public int PixelColorShiftTolerance { get; }
+ ///
+ /// Gets a value indicating whether metadata should be included in the comparison operation.
+ ///
+ public bool CompareMetadata { get; }
+
///
/// Calculates the difference between two images located at the specified file paths.
///
/// The comparison process may involve resizing the images or applying tolerances for
/// pixel color shifts and transparency, depending on the configured options.
- /// The absolute file path to the first image. This cannot be null or empty.
- /// The absolute file path to the second image. This cannot be null or empty.
+ /// The file path to the first image. This cannot be null or empty.
+ /// The file path to the second image. This cannot be null or empty.
/// An object representing the differences between the two images.
- public ICompareResult CalcDiff(string absolutePathPic1, string absolutePathPic2)
+ public ICompareResult CalcDiff(string pathImage1, string pathImage2)
{
- return Compare.CalcDiff(absolutePathPic1, absolutePathPic2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ var compareResult = Compare.CalcDiff(pathImage1, pathImage2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+
+ if (CompareMetadata)
+ {
+ var metadataDiff = MetadataComparer.CompareMetadata(pathImage1, pathImage2);
+ return new CompareResultWithMetadata(compareResult, metadataDiff);
+ }
+
+ return compareResult;
}
///
/// Calculates the difference between two images located at the specified file paths, using a provided difference mask.
///
- ///
- ///
+ ///
+ ///
///
///
- public ICompareResult CalcDiff(string absolutePathPic1, string absolutePathPic2, string differenceMask)
+ public ICompareResult CalcDiff(string pahtImage1, string pathImage2, string differenceMask)
+ {
+ var compareResult = Compare.CalcDiff(pahtImage1, pathImage2, differenceMask, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+
+ if (CompareMetadata)
+ {
+ var metadataDiff = MetadataComparer.CompareMetadata(pahtImage1, pathImage2);
+ return new CompareResultWithMetadata(compareResult, metadataDiff);
+ }
+
+ return compareResult;
+ }
+
+ ///
+ /// Calculates the difference between two in-memory images represented as objects.
+ ///
+ ///
+ ///
+ ///
+ public ICompareResult CalcDiff(SKBitmap image1, SKBitmap image2)
{
- return Compare.CalcDiff(absolutePathPic1, absolutePathPic2, differenceMask, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
+
+ if (CompareMetadata)
+ {
+ throw new NotSupportedException("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.");
+ }
+
+ return Compare.CalcDiffInternal(image1, image2, null, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Calculates the difference between two in-memory images represented as objects.
///
- ///
- ///
+ ///
+ ///
///
///
- public ICompareResult CalcDiff(SKBitmap absolutePic1, SKBitmap absolutePic2, SKBitmap differenceMaskPic)
+ public ICompareResult CalcDiff(SKBitmap image1, SKBitmap image2, SKBitmap differenceMaskPic)
{
- return Compare.CalcDiff(absolutePic1, absolutePic2, differenceMaskPic, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ if (CompareMetadata)
+ {
+ throw new NotSupportedException("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.");
+ }
+
+ return Compare.CalcDiff(image1, image2, differenceMaskPic, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Calculates the difference between two in-memory images represented as objects.
///
- ///
- ///
+ ///
+ ///
///
- public ICompareResult CalcDiff(FileStream pic1, FileStream pic2)
+ public ICompareResult CalcDiff(Stream image1, Stream image2)
{
- return Compare.CalcDiff(pic1, pic2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ var compareResult = Compare.CalcDiff(image1, image2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+
+ if (CompareMetadata)
+ {
+ if (image1.CanSeek)
+ {
+ image1.Position = 0;
+ }
+
+ if (image2.CanSeek)
+ {
+ image2.Position = 0;
+ }
+
+ var metadataDiff = MetadataComparer.CompareMetadata(image1, image2);
+
+ if (image1.CanSeek)
+ {
+ image1.Position = 0;
+ }
+
+ if (image2.CanSeek)
+ {
+ image2.Position = 0;
+ }
+
+ return new CompareResultWithMetadata(compareResult, metadataDiff);
+ }
+
+ return compareResult;
}
///
/// Calculates the difference between two images provided as file streams, using a specified mask image to focus the comparison.
///
- ///
- ///
+ ///
+ ///
///
///
- public ICompareResult CalcDiff(FileStream pic1, FileStream pic2, SKBitmap maskImage)
+ public ICompareResult CalcDiff(Stream image1, Stream image2, SKBitmap maskImage)
{
- return Compare.CalcDiff(pic1, pic2, maskImage, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ var compareResult = Compare.CalcDiff(image1, image2, maskImage, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+
+ if (CompareMetadata)
+ {
+ var metadataDiff = MetadataComparer.CompareMetadata(image1, image2);
+ return new CompareResultWithMetadata(compareResult, metadataDiff);
+ }
+
+ return compareResult;
}
///
/// Calculates a difference mask image that highlights the differences between two images located at the specified file paths.
///
- ///
- ///
+ ///
+ ///
///
- public SKBitmap CalcDiffMaskImage(string absolutePathPic1, string absolutePathPic2)
+ public SKBitmap CalcDiffMaskImage(string pathImage1, string pathImage2)
{
- return Compare.CalcDiffMaskImage(absolutePathPic1, absolutePathPic2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.CalcDiffMaskImage(pathImage1, pathImage2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Calculates a difference mask image that highlights the differences between two in-memory images represented as objects.
///
- ///
- ///
+ ///
+ ///
///
- public SKBitmap CalcDiffMaskImage(SKBitmap absolutePic1, SKBitmap absolutePic2)
+ public SKBitmap CalcDiffMaskImage(SKBitmap image1, SKBitmap image2)
{
- return Compare.CalcDiffMaskImage(absolutePic1, absolutePic2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.CalcDiffMaskImage(image1, image2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Calculates a difference mask image that highlights the differences between two images located at the specified file paths,
///
- ///
- ///
- ///
+ ///
+ ///
+ ///
///
- public SKBitmap CalcDiffMaskImage(string image1Path, string image2Path, string diffMask1Path)
+ public SKBitmap CalcDiffMaskImage(string pathImage1, string pathImage2, string pathDiffMask)
{
- return Compare.CalcDiffMaskImage(image1Path, image2Path, diffMask1Path, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.CalcDiffMaskImage(pathImage1, pathImage2, pathDiffMask, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Calculates a difference mask image that highlights the differences between two images provided as file streams.
///
- ///
- ///
+ ///
+ ///
///
- public SKBitmap CalcDiffMaskImage(FileStream image1Stream, FileStream image2Stream)
+ public SKBitmap CalcDiffMaskImage(Stream image1, Stream image2)
{
- return Compare.CalcDiffMaskImage(image1Stream, image2Stream, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.CalcDiffMaskImage(image1, image2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Calculates a difference mask image that highlights the differences between two images provided as file streams,
///
- ///
- ///
- ///
+ ///
+ ///
+ ///
///
- public SKBitmap CalcDiffMaskImage(FileStream image1Stream, FileStream image2Stream, FileStream diffMask1Stream)
+ public SKBitmap CalcDiffMaskImage(Stream image1, Stream image2, Stream diffMask)
{
- return Compare.CalcDiffMaskImage(image1Stream, image2Stream, diffMask1Stream, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.CalcDiffMaskImage(image1, image2, diffMask, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
@@ -168,55 +253,55 @@ public SKBitmap CalcDiffMaskImage(FileStream image1Stream, FileStream image2Stre
///
///
///
- ///
+ ///
///
- public SKBitmap CalcDiffMaskImage(SKBitmap image1, SKBitmap image2, SKBitmap diffMask1Image)
+ public SKBitmap CalcDiffMaskImage(SKBitmap image1, SKBitmap image2, SKBitmap diffMask)
{
- return Compare.CalcDiffMaskImage(image1, image2, diffMask1Image, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.CalcDiffMaskImage(image1, image2, diffMask, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
}
///
/// Checks if two images located at the specified file paths are identical, considering the configured options for resizing,
///
- ///
- ///
+ ///
+ ///
///
- public bool ImagesAreEqual(string absolutePathActual, string absolutePathExpected)
+ public bool ImagesAreEqual(string pathImage1, string pathImage2)
{
- return Compare.ImagesAreEqual(absolutePathActual, absolutePathExpected, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.ImagesAreEqual(pathImage1, pathImage2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions, CompareMetadata);
}
///
/// Checks if two images provided as file streams are identical, considering the configured options for resizing,
///
- ///
- ///
+ ///
+ ///
///
- public bool ImagesAreEqual(FileStream actual, FileStream expected)
+ public bool ImagesAreEqual(Stream image1, Stream image2)
{
- return Compare.ImagesAreEqual(actual, expected, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.ImagesAreEqual(image1, image2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions, CompareMetadata);
}
///
/// Checks if two in-memory images represented as objects are identical, considering the configured options for resizing,
///
- ///
- ///
+ ///
+ ///
///
- public bool ImagesAreEqual(SKBitmap actual, SKBitmap expected)
+ public bool ImagesAreEqual(SKBitmap image1, SKBitmap image2)
{
- return Compare.ImagesAreEqual(actual, expected, ResizeOption, PixelColorShiftTolerance, TransparencyOptions);
+ return Compare.ImagesAreEqual(image1, image2, ResizeOption, PixelColorShiftTolerance, TransparencyOptions, CompareMetadata);
}
///
/// Checks if two images have the same dimensions (width and height).
///
- ///
- ///
+ ///
+ ///
///
- public static bool ImagesHaveEqualSize(string absolutePathActual, string absolutePathExpected)
+ public static bool ImagesHaveEqualSize(string pathImage1, string pathImage2)
{
- return Compare.ImagesHaveEqualSize(absolutePathActual, absolutePathExpected);
+ return Compare.ImagesHaveEqualSize(pathImage1, pathImage2);
}
}
}
\ No newline at end of file
diff --git a/SkiaSharpCompare/MetadataComparer.cs b/SkiaSharpCompare/MetadataComparer.cs
new file mode 100644
index 0000000..c77e946
--- /dev/null
+++ b/SkiaSharpCompare/MetadataComparer.cs
@@ -0,0 +1,52 @@
+using SkiaSharpCompare.Metadata;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Codeuctivity.SkiaSharpCompare
+{
+ internal static class MetadataComparer
+ {
+ internal static Dictionary? CompareMetadata(string pathImageActual, string pathImageExpected)
+ {
+ var metaA = MetadataExtractorAdapter.Extract(pathImageActual);
+ var metaB = MetadataExtractorAdapter.Extract(pathImageExpected);
+
+ return GetMetadataDifferences(metaA, metaB);
+ }
+
+ internal static Dictionary? CompareMetadata(Stream imageActual, Stream imageExpected)
+ {
+ var metaA = MetadataExtractorAdapter.Extract(imageActual);
+ var metaB = MetadataExtractorAdapter.Extract(imageExpected);
+
+ return GetMetadataDifferences(metaA, metaB);
+ }
+
+ private static Dictionary? GetMetadataDifferences(IReadOnlyDictionary a, IReadOnlyDictionary b)
+ {
+ var diffs = new List<(string, string?, string?)>();
+ var allKeys = new HashSet(a.Keys, StringComparer.OrdinalIgnoreCase);
+ allKeys.UnionWith(b.Keys);
+
+ foreach (var key in allKeys.OrderBy(k => k, StringComparer.OrdinalIgnoreCase))
+ {
+ a.TryGetValue(key, out var valA);
+ b.TryGetValue(key, out var valB);
+
+ // Normalize whitespace for comparison
+ var normA = valA?.Trim() ?? string.Empty;
+ var normB = valB?.Trim() ?? string.Empty;
+
+ if (!string.Equals(normA, normB, StringComparison.Ordinal))
+ {
+ diffs.Add((key, valA, valB));
+ }
+ }
+
+ return diffs.ToDictionary(diff => diff.Item1, diff => (diff.Item2, diff.Item3)
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare/MetadataExtractorAdapter.cs b/SkiaSharpCompare/MetadataExtractorAdapter.cs
new file mode 100644
index 0000000..8fb10bf
--- /dev/null
+++ b/SkiaSharpCompare/MetadataExtractorAdapter.cs
@@ -0,0 +1,76 @@
+using MetadataExtractor;
+using System.Collections.Generic;
+using System.IO;
+
+namespace SkiaSharpCompare.Metadata
+{
+ ///
+ /// Provides static methods for extracting image metadata and returning it as a normalized dictionary of tag names
+ /// and values.
+ ///
+ /// This class serves as an adapter for reading metadata from image files or streams using the
+ /// underlying MetadataExtractor library. All returned tag keys are normalized in the format "Directory:TagName" for
+ /// consistency. The class is thread-safe as it contains only stateless static methods.
+ public static class MetadataExtractorAdapter
+ {
+ ///
+ /// Extracts metadata tags from the specified image stream and returns them as a normalized, case-insensitive
+ /// dictionary.
+ ///
+ /// The caller is responsible for ensuring that the provided stream is positioned at the
+ /// start of the image data and remains open for the duration of the operation. The returned dictionary uses
+ /// case-insensitive keys. If the stream is not seekable, consider passing a seekable copy to avoid
+ /// errors.
+ /// A seekable stream containing image data from which to read metadata. The stream must support reading and
+ /// seeking.
+ /// A read-only dictionary containing metadata tag names and their corresponding values extracted from the
+ /// image. The dictionary is empty if no metadata is found.
+ public static IReadOnlyDictionary Extract(Stream imageStream)
+ {
+ var map = new Dictionary(System.StringComparer.OrdinalIgnoreCase);
+
+ // MetadataExtractor reads from stream
+ var directories = ImageMetadataReader.ReadMetadata(imageStream);
+ return CreateResult(map, directories);
+ }
+
+ ///
+ /// Extracts metadata from the specified image file and returns it as a read-only dictionary of tag names and
+ /// values.
+ ///
+ /// The path to the image file from which to extract metadata. Cannot be null or empty.
+ /// A read-only dictionary containing metadata tag names and their corresponding values. The dictionary is empty
+ /// if no metadata is found.
+ public static IReadOnlyDictionary Extract(string imagePath)
+ {
+ var map = new Dictionary(System.StringComparer.OrdinalIgnoreCase);
+
+ // MetadataExtractor reads from stream
+ var directories = ImageMetadataReader.ReadMetadata(imagePath);
+ return CreateResult(map, directories);
+ }
+
+ private static Dictionary CreateResult(Dictionary map, IReadOnlyList directories)
+ {
+ foreach (var directory in directories)
+ {
+ foreach (var tag in directory.Tags)
+ {
+ // Normalize key as "Directory:TagName"
+ var key = $"{directory.Name}:{tag.Name}";
+ if (map.TryGetValue(key, out var existingValue))
+ {
+ // If duplicate keys occur, append with a separator
+ map[key] = existingValue + "; " + (tag.Description ?? string.Empty);
+ }
+ else
+ {
+ map[key] = tag.Description ?? string.Empty;
+ }
+ }
+ }
+
+ return map;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompare/SkiaSharpCompare.cs b/SkiaSharpCompare/SkiaSharpCompare.cs
index afe9ba9..cc16dd8 100644
--- a/SkiaSharpCompare/SkiaSharpCompare.cs
+++ b/SkiaSharpCompare/SkiaSharpCompare.cs
@@ -1,5 +1,6 @@
using SkiaSharp;
using System;
+using System.Collections.Generic;
using System.IO;
namespace Codeuctivity.SkiaSharpCompare
@@ -14,105 +15,138 @@ public static class Compare
///
/// Is true if width and height of both images are equal
///
- ///
- ///
+ ///
+ ///
///
- public static bool ImagesHaveEqualSize(string pathImageActual, string pathImageExpected)
+ public static bool ImagesHaveEqualSize(string pathImage1, string pathImage2)
{
- using var actualImage = SKBitmap.Decode(pathImageActual);
- using var expectedImage = SKBitmap.Decode(pathImageExpected);
- return ImagesHaveEqualSize(actualImage, expectedImage);
+ using var image1 = SKBitmap.Decode(pathImage1);
+ using var image2 = SKBitmap.Decode(pathImage2);
+ return ImagesHaveEqualSize(image1, image2);
}
///
/// Is true if width and height of both images are equal
///
- ///
- ///
+ ///
+ ///
///
- public static bool ImagesHaveEqualSize(Stream actual, Stream expected)
+ public static bool ImagesHaveEqualSize(Stream image1, Stream image2)
{
- using var actualImage = SKBitmap.Decode(actual);
- using var expectedImage = SKBitmap.Decode(expected);
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
+ using var actualImage = DecodeStream(image1);
+ using var expectedImage = DecodeStream(image2);
return ImagesHaveEqualSize(actualImage, expectedImage);
}
///
/// Is true if width and height of both images are equal
///
- ///
- ///
+ ///
+ ///
///
- public static bool ImagesHaveEqualSize(SKBitmap actualImage, SKBitmap expectedImage)
+ public static bool ImagesHaveEqualSize(SKBitmap image1, SKBitmap image2)
{
- return ImagesHaveSameDimension(actualImage, expectedImage);
+ return ImagesHaveSameDimension(image1, image2);
}
///
/// Compares two images for equivalence
///
- ///
- ///
+ ///
+ ///
///
///
///
+ /// If true, compares image metadata (EXIF, etc.) in addition to pixel data.
/// True if every pixel of actual is equal to expected
- public static bool ImagesAreEqual(string pathImageActual, string pathImageExpected, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static bool ImagesAreEqual(string pathImage1, string pathImage2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel, bool compareMetadata = false)
{
- using var actualImage = SKBitmap.Decode(pathImageActual);
- using var expectedImage = SKBitmap.Decode(pathImageExpected);
- return ImagesAreEqual(actualImage, expectedImage, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ if (compareMetadata)
+ {
+ var hasMetadataDiff = MetadataComparer.CompareMetadata(pathImage1, pathImage2)?.Count != 0;
+
+ if (hasMetadataDiff)
+ {
+ return false;
+ }
+ }
+
+ using var image1 = SKBitmap.Decode(pathImage1);
+ using var image2 = SKBitmap.Decode(pathImage2);
+ return ImagesAreEqual(image1, image2, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Compares two images for equivalence
///
- ///
- ///
+ ///
+ ///
///
///
///
+ /// If true, compares image metadata (EXIF, etc.) in addition to pixel data.
/// True if every pixel of actual is equal to expected
- public static bool ImagesAreEqual(Stream actual, Stream expected, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static bool ImagesAreEqual(Stream image1, Stream image2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel, bool compareMetadata = false)
{
- using var actualImage = SKBitmap.Decode(actual);
- using var expectedImage = SKBitmap.Decode(expected);
- return ImagesAreEqual(actualImage, expectedImage, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ if (compareMetadata)
+ {
+ var hasMetadataDiff = MetadataComparer.CompareMetadata(image1, image2)?.Count != 0;
+
+ if (hasMetadataDiff)
+ {
+ return false;
+ }
+ }
+
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
+
+ using var decodedImage1 = DecodeStream(image1);
+ using var decodedImage2 = DecodeStream(image2);
+ return ImagesAreEqual(decodedImage1, decodedImage2, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Compares two images for equivalence
///
- ///
- ///
+ ///
+ ///
///
///
///
+ /// If true, compares image metadata (EXIF, etc.) in addition to pixel data.
/// True if every pixel of actual is equal to expected
- public static bool ImagesAreEqual(SKBitmap actual, SKBitmap expected, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static bool ImagesAreEqual(SKBitmap image1, SKBitmap image2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel, bool compareMetadata = false)
{
- ArgumentNullException.ThrowIfNull(actual);
- ArgumentNullException.ThrowIfNull(expected);
+ if (compareMetadata)
+ {
+ throw new NotSupportedException("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.");
+ }
+
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
- if (resizeOption == ResizeOption.DontResize && !ImagesHaveSameDimension(actual, expected))
+ if (resizeOption == ResizeOption.DontResize && !ImagesHaveSameDimension(image1, image2))
{
return false;
}
- if (resizeOption == ResizeOption.DontResize || ImagesHaveSameDimension(actual, expected))
+ if (resizeOption == ResizeOption.DontResize || ImagesHaveSameDimension(image1, image2))
{
- for (var x = 0; x < actual.Width; x++)
+ for (var x = 0; x < image1.Width; x++)
{
- for (var y = 0; y < actual.Height; y++)
+ for (var y = 0; y < image1.Height; y++)
{
- if (transparencyOptions == TransparencyOptions.CompareAlphaChannel && pixelColorShiftTolerance == 0 && !actual.GetPixel(x, y).Equals(expected.GetPixel(x, y)))
+ if (transparencyOptions == TransparencyOptions.CompareAlphaChannel && pixelColorShiftTolerance == 0 && !image1.GetPixel(x, y).Equals(image2.GetPixel(x, y)))
{
return false;
}
else
{
- var actualPixel = actual.GetPixel(x, y);
- var expectedPixel = expected.GetPixel(x, y);
+ var actualPixel = image1.GetPixel(x, y);
+ var expectedPixel = image2.GetPixel(x, y);
var a = 0;
if (transparencyOptions == TransparencyOptions.CompareAlphaChannel)
@@ -136,7 +170,7 @@ public static bool ImagesAreEqual(SKBitmap actual, SKBitmap expected, ResizeOpti
return true;
}
- var grown = GrowToSameDimension(actual, expected);
+ var grown = GrowToSameDimension(image1, image2);
try
{
return ImagesAreEqual(grown.Item1, grown.Item2, ResizeOption.DontResize);
@@ -151,54 +185,117 @@ public static bool ImagesAreEqual(SKBitmap actual, SKBitmap expected, ResizeOpti
///
/// Calculates ICompareResult expressing the amount of difference of both images
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Mean and absolute pixel error
+ public static ICompareResult CalcDiff(string pathImage1, string pathImage2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.IgnoreAlphaChannel)
+ {
+ using var actual = SKBitmap.Decode(pathImage1);
+ using var expected = SKBitmap.Decode(pathImage2);
+ return CalcDiffInternal(actual, expected, null, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ }
+
+ ///
+ /// Calculates ICompareResult expressing the amount of difference of both images
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Mean and absolute pixel error
+ public static ICompareResult CalcDiff(Stream image1, Stream image2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.IgnoreAlphaChannel)
+ {
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
+
+ using var actual = DecodeStream(image1);
+ using var expected = DecodeStream(image2);
+ return CalcDiffInternal(actual, expected, null, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ }
+
+ ///
+ /// Calculates ICompareResult expressing the amount of difference of both images using a mask image for tolerated difference between the two images
+ ///
///
///
+ ///
///
///
///
/// Mean and absolute pixel error
- public static ICompareResult CalcDiff(string pathActualImage, string pathExpectedImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.IgnoreAlphaChannel)
+ public static ICompareResult CalcDiff(string pathActualImage, string pathExpectedImage, string pathMaskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- using var actual = SKBitmap.Decode(pathActualImage);
- using var expected = SKBitmap.Decode(pathExpectedImage);
- return CalcDiff(actual, expected, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ using var image1 = SKBitmap.Decode(pathActualImage);
+ using var image2 = SKBitmap.Decode(pathExpectedImage);
+ using var mask = SKBitmap.Decode(pathMaskImage);
+ return CalcDiff(image1, image2, mask, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Calculates ICompareResult expressing the amount of difference of both images
///
- ///
- ///
+ ///
+ ///
+ ///
///
///
///
- /// Mean and absolute pixel error
- public static ICompareResult CalcDiff(Stream actualImage, Stream expectedImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.IgnoreAlphaChannel)
+ ///
+ public static ICompareResult CalcDiff(Stream image1, Stream image2, SKBitmap maskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ {
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
+ ArgumentNullException.ThrowIfNull(maskImage);
+
+ using var actual = DecodeStream(image1);
+ using var expected = DecodeStream(image2);
+ return CalcDiff(actual, expected, maskImage, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ }
+
+ ///
+ /// Compares two images for equivalence
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ICompareResult CalcDiff(SKBitmap image1, SKBitmap image2, SKBitmap maskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- using var actual = SKBitmap.Decode(actualImage);
- using var expected = SKBitmap.Decode(expectedImage);
- return CalcDiff(actual, expected, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
+ ArgumentNullException.ThrowIfNull(maskImage);
+
+ var metadataDifference = new Dictionary();
+ return CalcDiff(image1, image2, maskImage, metadataDifference, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Calculates ICompareResult expressing the amount of difference of both images
///
- ///
- ///
+ ///
+ ///
+ ///
///
///
///
/// Mean and absolute pixel error
- public static ICompareResult CalcDiff(SKBitmap actual, SKBitmap expected, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.IgnoreAlphaChannel)
+ internal static ICompareResult CalcDiffInternal(SKBitmap image1, SKBitmap image2, Dictionary? metadataDifference, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.IgnoreAlphaChannel)
{
- var imagesHaveSameDimension = ImagesHaveSameDimension(actual, expected);
+ var imagesHaveSameDimension = ImagesHaveSameDimension(image1, image2);
if (resizeOption == ResizeOption.Resize && !imagesHaveSameDimension)
{
- var grown = GrowToSameDimension(actual, expected);
+ var grown = GrowToSameDimension(image1, image2);
try
{
- return CalcDiff(grown.Item1, grown.Item2, ResizeOption.DontResize, pixelColorShiftTolerance, transparencyOptions);
+ return CalcDiffInternal(grown.Item1, grown.Item2, metadataDifference, ResizeOption.DontResize, pixelColorShiftTolerance, transparencyOptions);
}
finally
{
@@ -207,21 +304,21 @@ public static ICompareResult CalcDiff(SKBitmap actual, SKBitmap expected, Resize
}
}
- if (!ImagesHaveSameDimension(actual, expected))
+ if (!ImagesHaveSameDimension(image1, image2))
{
throw new SkiaSharpCompareException(sizeDiffersExceptionMessage);
}
- var quantity = actual.Width * actual.Height;
+ var quantity = image1.Width * image1.Height;
var absoluteError = 0;
var pixelErrorCount = 0;
- for (var x = 0; x < actual.Width; x++)
+ for (var x = 0; x < image1.Width; x++)
{
- for (var y = 0; y < actual.Height; y++)
+ for (var y = 0; y < image1.Height; y++)
{
- var actualPixel = actual.GetPixel(x, y);
- var expectedPixel = expected.GetPixel(x, y);
+ var actualPixel = image1.GetPixel(x, y);
+ var expectedPixel = image2.GetPixel(x, y);
var r = Math.Abs(expectedPixel.Red - actualPixel.Red);
var g = Math.Abs(expectedPixel.Green - actualPixel.Green);
@@ -230,72 +327,51 @@ public static ICompareResult CalcDiff(SKBitmap actual, SKBitmap expected, Resize
if (transparencyOptions == TransparencyOptions.CompareAlphaChannel)
{
var a = Math.Abs(expectedPixel.Alpha - actualPixel.Alpha);
- sum = sum + a;
+ sum += a;
}
- absoluteError = absoluteError + (sum > pixelColorShiftTolerance ? sum : 0);
+ absoluteError += (sum > pixelColorShiftTolerance ? sum : 0);
pixelErrorCount += (sum > pixelColorShiftTolerance) ? 1 : 0;
}
}
var meanError = (double)absoluteError / quantity;
var pixelErrorPercentage = (double)pixelErrorCount / quantity * 100;
- return new CompareResult(absoluteError, meanError, pixelErrorCount, pixelErrorPercentage);
+ return new CompareResult(absoluteError, meanError, pixelErrorCount, pixelErrorPercentage, metadataDifference);
}
- ///
- /// Calculates ICompareResult expressing the amount of difference of both images using a mask image for tolerated difference between the two images
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// Mean and absolute pixel error
- public static ICompareResult CalcDiff(string pathActualImage, string pathExpectedImage, string pathMaskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ private static SKBitmap DecodeStream(Stream stream)
{
- using var actual = SKBitmap.Decode(pathActualImage);
- using var expected = SKBitmap.Decode(pathExpectedImage);
- using var mask = SKBitmap.Decode(pathMaskImage);
- return CalcDiff(actual, expected, mask, resizeOption, pixelColorShiftTolerance, transparencyOptions);
- }
+ // Addressing https://github.com/mono/SkiaSharp/issues/2263
- ///
- /// Calculates ICompareResult expressing the amount of difference of both images
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static ICompareResult CalcDiff(Stream actualImage, Stream expectedImage, SKBitmap maskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
- {
- using var actual = SKBitmap.Decode(actualImage);
- using var expected = SKBitmap.Decode(expectedImage);
- return CalcDiff(actual, expected, maskImage, resizeOption, pixelColorShiftTolerance, transparencyOptions);
+ using var copy = new MemoryStream();
+
+ if (stream.CanSeek)
+ {
+ stream.Position = 0;
+ }
+
+ stream.CopyTo(copy);
+
+ if (stream.CanSeek)
+ {
+ stream.Position = 0;
+ }
+
+ var bytes = copy.ToArray();
+ using var skData = SKData.CreateCopy(bytes);
+
+ return SKBitmap.Decode(skData);
}
- ///
- /// Compares two images for equivalence
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static ICompareResult CalcDiff(SKBitmap actual, SKBitmap expected, SKBitmap maskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ internal static ICompareResult CalcDiff(SKBitmap image1, SKBitmap image2, SKBitmap maskImage, Dictionary metadataDifference, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
ArgumentNullException.ThrowIfNull(maskImage);
- var imagesHaveSameDimension = ImagesHaveSameDimension(actual, expected) && ImagesHaveSameDimension(actual, maskImage);
+ var imagesHaveSameDimension = ImagesHaveSameDimension(image1, image2) && ImagesHaveSameDimension(image1, maskImage);
if (resizeOption == ResizeOption.Resize && !imagesHaveSameDimension)
{
- var grown = GrowToSameDimension(actual, expected, maskImage);
+ var grown = GrowToSameDimension(image1, image2, maskImage);
try
{
return CalcDiff(grown.Item1, grown.Item2, grown.Item3, ResizeOption.DontResize, pixelColorShiftTolerance, transparencyOptions);
@@ -313,17 +389,17 @@ public static ICompareResult CalcDiff(SKBitmap actual, SKBitmap expected, SKBitm
throw new SkiaSharpCompareException(sizeDiffersExceptionMessage);
}
- var quantity = actual.Width * actual.Height;
+ var quantity = image1.Width * image1.Height;
var absoluteError = 0;
var pixelErrorCount = 0;
- for (var x = 0; x < actual.Width; x++)
+ for (var x = 0; x < image1.Width; x++)
{
- for (var y = 0; y < actual.Height; y++)
+ for (var y = 0; y < image1.Height; y++)
{
var maskImagePixel = maskImage.GetPixel(x, y);
- var actualPixel = actual.GetPixel(x, y);
- var expectedPixel = expected.GetPixel(x, y);
+ var actualPixel = image1.GetPixel(x, y);
+ var expectedPixel = image2.GetPixel(x, y);
var r = Math.Abs(expectedPixel.Red - actualPixel.Red);
var g = Math.Abs(expectedPixel.Green - actualPixel.Green);
@@ -355,13 +431,13 @@ public static ICompareResult CalcDiff(SKBitmap actual, SKBitmap expected, SKBitm
}
}
- absoluteError = absoluteError + (error > pixelColorShiftTolerance ? error : 0);
+ absoluteError += (error > pixelColorShiftTolerance ? error : 0);
pixelErrorCount += error > pixelColorShiftTolerance ? 1 : 0;
}
}
var meanError = (double)absoluteError / quantity;
var pixelErrorPercentage = (double)pixelErrorCount / quantity * 100;
- return new CompareResult(absoluteError, meanError, pixelErrorCount, pixelErrorPercentage);
+ return new CompareResult(absoluteError, meanError, pixelErrorCount, pixelErrorPercentage, metadataDifference);
}
private static bool ImagesHaveSameDimension(SKBitmap actual, SKBitmap expected)
@@ -375,33 +451,33 @@ private static bool ImagesHaveSameDimension(SKBitmap actual, SKBitmap expected)
///
/// Creates a diff mask image of two images
///
- ///
- ///
+ ///
+ ///
///
///
///
/// Image representing diff, black means no diff between actual image and expected image, white means max diff
- public static SKBitmap CalcDiffMaskImage(string pathActualImage, string pathExpectedImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static SKBitmap CalcDiffMaskImage(string pathImage1, string pathImage2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- using var actual = SKBitmap.Decode(pathActualImage);
- using var expected = SKBitmap.Decode(pathExpectedImage);
+ using var actual = SKBitmap.Decode(pathImage1);
+ using var expected = SKBitmap.Decode(pathImage2);
return CalcDiffMaskImage(actual, expected, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Creates a diff mask image of two images
///
- ///
- ///
+ ///
+ ///
///
///
///
///
/// Image representing diff, black means no diff between actual image and expected image, white means max diff
- public static SKBitmap CalcDiffMaskImage(string pathActualImage, string pathExpectedImage, string pathMaskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static SKBitmap CalcDiffMaskImage(string pathImage1, string pathImage2, string pathMaskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- using var actual = SKBitmap.Decode(pathActualImage);
- using var expected = SKBitmap.Decode(pathExpectedImage);
+ using var actual = SKBitmap.Decode(pathImage1);
+ using var expected = SKBitmap.Decode(pathImage2);
using var mask = SKBitmap.Decode(pathMaskImage);
return CalcDiffMaskImage(actual, expected, mask, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
@@ -409,97 +485,58 @@ public static SKBitmap CalcDiffMaskImage(string pathActualImage, string pathExpe
///
/// Creates a diff mask image of two images
///
- ///
- ///
+ ///
+ ///
///
///
///
/// Image representing diff, black means no diff between actual image and expected image, white means max diff
- public static SKBitmap CalcDiffMaskImage(Stream actualImage, Stream expectedImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static SKBitmap CalcDiffMaskImage(Stream image1, Stream image2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- ArgumentNullException.ThrowIfNull(actualImage);
-
- ArgumentNullException.ThrowIfNull(expectedImage);
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
- if (actualImage.CanSeek)
- {
- actualImage.Position = 0;
- }
- if (expectedImage.CanSeek)
- {
- expectedImage.Position = 0;
- }
+ using var actual = DecodeStream(image1);
+ using var expected = DecodeStream(image2);
- using var actualImageCopy = new MemoryStream();
- using var expectedImageCopy = new MemoryStream();
- actualImage.CopyTo(actualImageCopy);
- expectedImage.CopyTo(expectedImageCopy);
- actualImageCopy.Position = 0;
- expectedImageCopy.Position = 0;
- using var actual = SKBitmap.Decode(actualImageCopy);
- using var expected = SKBitmap.Decode(expectedImageCopy);
return CalcDiffMaskImage(actual, expected, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Creates a diff mask image of two images
///
- ///
- ///
+ ///
+ ///
///
///
///
///
/// Image representing diff, black means no diff between actual image and expected image, white means max diff
- public static SKBitmap CalcDiffMaskImage(Stream actualImage, Stream expectedImage, Stream maskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static SKBitmap CalcDiffMaskImage(Stream image1, Stream image2, Stream maskImage, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- ArgumentNullException.ThrowIfNull(actualImage);
-
- ArgumentNullException.ThrowIfNull(expectedImage);
-
+ ArgumentNullException.ThrowIfNull(image1);
+ ArgumentNullException.ThrowIfNull(image2);
ArgumentNullException.ThrowIfNull(maskImage);
- if (actualImage.CanSeek)
- {
- actualImage.Position = 0;
- }
- if (expectedImage.CanSeek)
- {
- expectedImage.Position = 0;
- }
-
- if (maskImage.CanSeek)
- {
- maskImage.Position = 0;
- }
+ using var actual = DecodeStream(image1);
+ using var expected = DecodeStream(image2);
+ using var mask = DecodeStream(maskImage);
- using var actualImageCopy = new MemoryStream();
- using var expectedImageCopy = new MemoryStream();
- using var maskCopy = new MemoryStream();
- actualImage.CopyTo(actualImageCopy);
- expectedImage.CopyTo(expectedImageCopy);
- maskImage.CopyTo(maskCopy);
- actualImageCopy.Position = 0;
- expectedImageCopy.Position = 0;
- maskCopy.Position = 0;
- using var actual = SKBitmap.Decode(actualImageCopy);
- using var expected = SKBitmap.Decode(expectedImageCopy);
- using var mask = SKBitmap.Decode(maskCopy);
return CalcDiffMaskImage(actual, expected, mask, resizeOption, pixelColorShiftTolerance, transparencyOptions);
}
///
/// Creates a diff mask image of two images
///
- ///
- ///
+ ///
+ ///
///
///
///
/// Image representing diff, black means no diff between actual image and expected image, white means max diff
- public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static SKBitmap CalcDiffMaskImage(SKBitmap image1, SKBitmap image2, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
- var imagesHAveSameDimension = ImagesHaveSameDimension(actual, expected);
+ var imagesHAveSameDimension = ImagesHaveSameDimension(image1, image2);
if (resizeOption == ResizeOption.DontResize && !imagesHAveSameDimension)
{
@@ -508,14 +545,14 @@ public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, Res
if (imagesHAveSameDimension)
{
- var maskImage = new SKBitmap(actual.Width, actual.Height);
+ var maskImage = new SKBitmap(image1.Width, image1.Height);
- for (var x = 0; x < actual.Width; x++)
+ for (var x = 0; x < image1.Width; x++)
{
- for (var y = 0; y < actual.Height; y++)
+ for (var y = 0; y < image1.Height; y++)
{
- var actualPixel = actual.GetPixel(x, y);
- var expectedPixel = expected.GetPixel(x, y);
+ var actualPixel = image1.GetPixel(x, y);
+ var expectedPixel = image2.GetPixel(x, y);
var red = (byte)Math.Abs(actualPixel.Red - expectedPixel.Red);
var green = (byte)Math.Abs(actualPixel.Green - expectedPixel.Green);
@@ -581,7 +618,7 @@ public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, Res
return maskImage;
}
- var grown = GrowToSameDimension(actual, expected);
+ var grown = GrowToSameDimension(image1, image2);
try
{
return CalcDiffMaskImage(grown.Item1, grown.Item2, ResizeOption.DontResize, pixelColorShiftTolerance, transparencyOptions);
@@ -596,18 +633,18 @@ public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, Res
///
/// Creates a diff mask image of two images
///
- ///
- ///
+ ///
+ ///
///
///
///
///
/// Image representing diff, black means no diff between actual image and expected image, white means max diff
- public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, SKBitmap mask, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
+ public static SKBitmap CalcDiffMaskImage(SKBitmap image1, SKBitmap image2, SKBitmap mask, ResizeOption resizeOption = ResizeOption.DontResize, int pixelColorShiftTolerance = 0, TransparencyOptions transparencyOptions = TransparencyOptions.CompareAlphaChannel)
{
ArgumentNullException.ThrowIfNull(mask);
- var imagesHaveSameDimension = ImagesHaveSameDimension(actual, expected) && ImagesHaveSameDimension(actual, mask);
+ var imagesHaveSameDimension = ImagesHaveSameDimension(image1, image2) && ImagesHaveSameDimension(image1, mask);
if (resizeOption == ResizeOption.DontResize && !imagesHaveSameDimension)
{
@@ -616,14 +653,14 @@ public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, SKB
if (imagesHaveSameDimension)
{
- var maskImage = new SKBitmap(actual.Width, actual.Height);
+ var maskImage = new SKBitmap(image1.Width, image1.Height);
- for (var x = 0; x < actual.Width; x++)
+ for (var x = 0; x < image1.Width; x++)
{
- for (var y = 0; y < actual.Height; y++)
+ for (var y = 0; y < image1.Height; y++)
{
- var actualPixel = actual.GetPixel(x, y);
- var expectedPixel = expected.GetPixel(x, y);
+ var actualPixel = image1.GetPixel(x, y);
+ var expectedPixel = image2.GetPixel(x, y);
var maskPixel = mask.GetPixel(x, y);
var redDiff = Math.Abs(actualPixel.Red - expectedPixel.Red);
@@ -692,7 +729,7 @@ public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, SKB
return maskImage;
}
- var grown = GrowToSameDimension(actual, expected, mask);
+ var grown = GrowToSameDimension(image1, image2, mask);
try
{
return CalcDiffMaskImage(grown.Item1, grown.Item2, grown.Item3, ResizeOption.DontResize, pixelColorShiftTolerance, transparencyOptions);
@@ -705,26 +742,26 @@ public static SKBitmap CalcDiffMaskImage(SKBitmap actual, SKBitmap expected, SKB
}
}
- private static (SKBitmap, SKBitmap) GrowToSameDimension(SKBitmap actual, SKBitmap expected)
+ private static (SKBitmap, SKBitmap) GrowToSameDimension(SKBitmap image1, SKBitmap image2)
{
- var biggestWidth = actual.Width > expected.Width ? actual.Width : expected.Width;
- var biggestHeight = actual.Height > expected.Height ? actual.Height : expected.Height;
+ var biggestWidth = image1.Width > image2.Width ? image1.Width : image2.Width;
+ var biggestHeight = image1.Height > image2.Height ? image1.Height : image2.Height;
var skSize = new SKSizeI(biggestWidth, biggestHeight);
- var grownExpected = expected.Resize(skSize, SKSamplingOptions.Default);
- var grownActual = actual.Resize(skSize, SKSamplingOptions.Default);
+ var grownExpected = image2.Resize(skSize, SKSamplingOptions.Default);
+ var grownActual = image1.Resize(skSize, SKSamplingOptions.Default);
return (grownActual, grownExpected);
}
- private static (SKBitmap, SKBitmap, SKBitmap) GrowToSameDimension(SKBitmap actual, SKBitmap expected, SKBitmap mask)
+ private static (SKBitmap, SKBitmap, SKBitmap) GrowToSameDimension(SKBitmap image1, SKBitmap image2, SKBitmap mask)
{
- var biggestWidth = actual.Width > expected.Width ? actual.Width : expected.Width;
+ var biggestWidth = image1.Width > image2.Width ? image1.Width : image2.Width;
biggestWidth = biggestWidth > mask.Width ? biggestWidth : mask.Width;
- var biggestHeight = actual.Height > expected.Height ? actual.Height : expected.Height;
+ var biggestHeight = image1.Height > image2.Height ? image1.Height : image2.Height;
biggestHeight = biggestHeight > mask.Height ? biggestHeight : mask.Height;
var skSize = new SKSizeI(biggestWidth, biggestHeight);
- var grownExpected = expected.Resize(skSize, SKSamplingOptions.Default);
- var grownActual = actual.Resize(skSize, SKSamplingOptions.Default);
+ var grownExpected = image2.Resize(skSize, SKSamplingOptions.Default);
+ var grownActual = image1.Resize(skSize, SKSamplingOptions.Default);
var grownMask = mask.Resize(skSize, SKSamplingOptions.Default);
return (grownActual, grownExpected, grownMask);
diff --git a/SkiaSharpCompare/SkiaSharpCompare.csproj b/SkiaSharpCompare/SkiaSharpCompare.csproj
index b72b88d..339a4c3 100644
--- a/SkiaSharpCompare/SkiaSharpCompare.csproj
+++ b/SkiaSharpCompare/SkiaSharpCompare.csproj
@@ -38,16 +38,16 @@
Codeuctivity.SkiaSharpCompare
Codeuctivity.SkiaSharpCompare
true
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs
new file mode 100644
index 0000000..8692ac4
--- /dev/null
+++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_PathTests.cs
@@ -0,0 +1,95 @@
+using Codeuctivity.SkiaSharpCompare;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace SkiaSharpCompareTestNunit
+{
+ internal class SkiaSharpCompareMetaData_PathTests
+ {
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, false, true)]
+ [TestCase(TestFiles.imageWithoutGpsMetadata, TestFiles.imageWithGpsMetadata, true, false)]
+ [TestCase(TestFiles.imageWithoutGpsMetadata, TestFiles.imageWithGpsMetadata, false, true)]
+ public void ImagesAreEqual_SamePixelComparedByMetadataShouldReturnResult(string pic1Path, string pic2Path, bool shouldCompareMetadata, bool expectOutcomeComparisonOfImage)
+ {
+ var pic1 = Path.Combine(AppContext.BaseDirectory, pic1Path);
+ var pic2 = Path.Combine(AppContext.BaseDirectory, pic2Path);
+
+ var sut = new ImageCompare(compareMetadata: shouldCompareMetadata);
+ Assert.That(sut.ImagesAreEqual(pic1, pic2), Is.EqualTo(expectOutcomeComparisonOfImage));
+ }
+
+ [Test]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnResult_Null()
+ {
+ var pic1 = Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithGpsMetadata);
+ var pic2 = Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata);
+
+ var sut = new ImageCompare(compareMetadata: false);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ Assert.That(actual.MetadataDifferences, Is.Null);
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ [Test]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnEmptyResult()
+ {
+ var pic1 = Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata);
+ var pic2 = Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata);
+
+ var sut = new ImageCompare(compareMetadata: true);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ Assert.That(actual.MetadataDifferences, Is.Empty);
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ [Test]
+ [SetCulture("en-US")]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnCollectionOfMetadataThatDiffers()
+ {
+ var pic1 = Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata);
+ var pic2 = Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithGpsMetadata);
+
+ var sut = new ImageCompare(compareMetadata: true);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ // Output actual and expected to test run logs for easier diagnosis
+ TestContext.WriteLine($"Actual image: {pic1}");
+ TestContext.WriteLine($"Expected image: {pic2}");
+ TestContext.WriteLine($"Actual MetadataDifferences: {FormatMetadata(actual.MetadataDifferences)}");
+
+ var expected = new Dictionary
+ {
+ { "File:File Name", (Path.GetFileName(pic1), Path.GetFileName(pic2)) },
+ { "GPS:GPS Altitude", ("0 metres", "201.62 metres") },
+ { "GPS:GPS Date Stamp", ("", "2025:01:03") },
+ { "GPS:GPS Latitude", ("0° 0' 0\"", "48° 12' 7.17\"") },
+ { "GPS:GPS Latitude Ref", ("", "N") },
+ { "GPS:GPS Longitude", ("0° 0' 0\"", "16° 24' 7.53\"") },
+ { "GPS:GPS Longitude Ref", ("", "E") },
+ { "GPS:GPS Processing Method", ("", "GPS") },
+ { "GPS:GPS Time-Stamp", ("00:00:00.000 UTC", "14:41:20.000 UTC") }
+ };
+
+ TestContext.WriteLine($"Expected MetadataDifferences: {FormatMetadata(expected)}");
+
+ Assert.That(actual.MetadataDifferences, Is.EqualTo(expected));
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ private static string FormatMetadata(Dictionary? metadata)
+ {
+ if (metadata is null)
+ {
+ return "null";
+ }
+
+ return string.Join("; ", metadata.Select(kvp => $"{kvp.Key}=[{kvp.Value.ValueA ?? ""} | {kvp.Value.ValueB ?? ""}]"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs
new file mode 100644
index 0000000..5a3386a
--- /dev/null
+++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_SkBitmap.cs
@@ -0,0 +1,84 @@
+using Codeuctivity.SkiaSharpCompare;
+using NUnit.Framework;
+using SkiaSharp;
+using System;
+using System.IO;
+
+namespace SkiaSharpCompareTestNunit
+{
+ internal class SkiaSharpCompareMetaData_SkBitmap
+ {
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.imageWithoutGpsMetadata, TestFiles.imageWithGpsMetadata)]
+ public void ImagesAreEqual_SamePixelComparedByMetadataShouldReturnResult(string pic1Path, string pic2Path)
+ {
+ var pic1 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, pic1Path));
+ var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, pic2Path));
+
+ var sut = new ImageCompare(compareMetadata: false);
+ Assert.That(sut.ImagesAreEqual(pic1, pic2));
+ }
+
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.imageWithoutGpsMetadata, TestFiles.imageWithGpsMetadata)]
+ public void ImagesAreEqual_SamePixelComparedByMetadataShouldThrows(string pic1Path, string pic2Path)
+ {
+ var pic1 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, pic1Path));
+ var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, pic2Path));
+
+ var sut = new ImageCompare(compareMetadata: true);
+
+ var ex = Assert.Throws(() =>
+ {
+ sut.ImagesAreEqual(pic1, pic2);
+ });
+
+ 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."));
+ }
+
+ [Test]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnResult_Null()
+ {
+ var pic1 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithGpsMetadata));
+ var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata));
+
+ var sut = new ImageCompare(compareMetadata: false);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ Assert.That(actual.MetadataDifferences, Is.Null);
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ [Test]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnEmptyResult()
+ {
+ var pic1 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata));
+ var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata));
+
+ var sut = new ImageCompare(compareMetadata: true);
+ var ex = Assert.Throws(() =>
+ {
+ sut.CalcDiff(pic1, pic2);
+ });
+
+ 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."));
+ }
+
+ [Test]
+ [SetCulture("en-US")]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnCollectionOfMetadataThatDiffers()
+ {
+ var pic1 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithoutGpsMetadata));
+ var pic2 = SKBitmap.Decode(Path.Combine(AppContext.BaseDirectory, TestFiles.imageWithGpsMetadata));
+
+ var sut = new ImageCompare(compareMetadata: true);
+
+ var ex = Assert.Throws(() =>
+ {
+ sut.CalcDiff(pic1, pic2);
+ });
+
+ 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."));
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_StreamTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_StreamTests.cs
new file mode 100644
index 0000000..5490fc2
--- /dev/null
+++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareMetaData_StreamTests.cs
@@ -0,0 +1,92 @@
+using Codeuctivity.SkiaSharpCompare;
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace SkiaSharpCompareTestNunit
+{
+ internal class SkiaSharpCompareMetaData_StreamTests
+ {
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, false, true)]
+ [TestCase(TestFiles.imageWithoutGpsMetadata, TestFiles.imageWithGpsMetadata, true, false)]
+ [TestCase(TestFiles.imageWithoutGpsMetadata, TestFiles.imageWithGpsMetadata, false, true)]
+ public void ImagesAreEqual_SamePixelComparedByMetadataShouldReturnResult(string pic1Path, string pic2Path, bool shouldCompareMetadata, bool expectOutcomeComparisonOfImage)
+ {
+ using var pic1 = File.OpenRead(pic1Path);
+ using var pic2 = File.OpenRead(pic2Path);
+
+ var sut = new ImageCompare(compareMetadata: shouldCompareMetadata);
+ Assert.That(sut.ImagesAreEqual(pic1, pic2), Is.EqualTo(expectOutcomeComparisonOfImage));
+ }
+
+ [Test]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnResult_Null()
+ {
+ using var pic1 = File.OpenRead(TestFiles.imageWithoutGpsMetadata);
+ using var pic2 = File.OpenRead(TestFiles.imageWithoutGpsMetadata);
+
+ var sut = new ImageCompare(compareMetadata: false);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ Assert.That(actual.MetadataDifferences, Is.Null);
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ [Test]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnEmptyResult()
+ {
+ using var pic1 = File.OpenRead(TestFiles.imageWithoutGpsMetadata);
+ using var pic2 = File.OpenRead(TestFiles.imageWithoutGpsMetadata);
+
+ var sut = new ImageCompare(compareMetadata: true);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ Assert.That(actual.MetadataDifferences, Is.Empty);
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ [Test]
+ [SetCulture("en-US")]
+ public void CalcDiff_SamePixelComparedByMetadataShouldReturnCollectionOfMetadataThatDiffers()
+ {
+ using var pic1 = File.OpenRead(TestFiles.imageWithoutGpsMetadata);
+ using var pic2 = File.OpenRead(TestFiles.imageWithGpsMetadata);
+ var sut = new ImageCompare(compareMetadata: true);
+ var actual = sut.CalcDiff(pic1, pic2);
+
+ // Output actual and expected to test run logs for easier diagnosis
+ TestContext.WriteLine($"Actual image: {pic1}");
+ TestContext.WriteLine($"Expected image: {pic2}");
+ TestContext.WriteLine($"Actual MetadataDifferences: {FormatMetadata(actual.MetadataDifferences)}");
+
+ var expected = new Dictionary
+ {
+ { "GPS:GPS Altitude", ("0 metres", "201.62 metres") },
+ { "GPS:GPS Date Stamp", ("", "2025:01:03") },
+ { "GPS:GPS Latitude", ("0° 0' 0\"", "48° 12' 7.17\"") },
+ { "GPS:GPS Latitude Ref", ("", "N") },
+ { "GPS:GPS Longitude", ("0° 0' 0\"", "16° 24' 7.53\"") },
+ { "GPS:GPS Longitude Ref", ("", "E") },
+ { "GPS:GPS Processing Method", ("", "GPS") },
+ { "GPS:GPS Time-Stamp", ("00:00:00.000 UTC", "14:41:20.000 UTC") }
+ };
+
+ TestContext.WriteLine($"Expected MetadataDifferences: {FormatMetadata(expected)}");
+
+ Assert.That(actual.MetadataDifferences, Is.EqualTo(expected));
+ Assert.That(actual.PixelErrorCount, Is.Zero);
+ }
+
+ private static string FormatMetadata(Dictionary? metadata)
+ {
+ if (metadata is null)
+ {
+ return "null";
+ }
+
+ return string.Join("; ", metadata.Select(kvp => $"{kvp.Key}=[{kvp.Value.ValueA ?? ""} | {kvp.Value.ValueB ?? ""}]"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj b/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj
index 8aa6580..1a6ae10 100644
--- a/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj
+++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareTestNunit.csproj
@@ -13,19 +13,15 @@
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 afd4505..8ab5f5c 100644
--- a/SkiaSharpCompareTestNunit/SkiaSharpCompareTests.cs
+++ b/SkiaSharpCompareTestNunit/SkiaSharpCompareTests.cs
@@ -8,26 +8,12 @@ namespace SkiaSharpCompareTestNunit
{
public class SkiaSharpCompareTests
{
- private const string jpg0Rgb24 = "../../../TestData/Calc0.jpg";
- private const string jpg1Rgb24 = "../../../TestData/Calc1.jpg";
- private const string png0Rgba32 = "../../../TestData/Calc0.png";
- private const string png1Rgba32 = "../../../TestData/Calc1.png";
- private const string pngBlack2x2px = "../../../TestData/Black.png";
- private const string pngBlack4x4px = "../../../TestData/BlackDoubleSize.png";
- private const string pngWhite2x2px = "../../../TestData/White.png";
- private const string pngTransparent2x2px = "../../../TestData/pngTransparent2x2px.png";
- private const string pngPartialTransparent2x2px = "../../../TestData/pngPartialTransparent2x2px.png";
- private const string renderedForm1 = "../../../TestData/HC007-Test-02-3-OxPt.html1.png";
- private const string renderedForm2 = "../../../TestData/HC007-Test-02-3-OxPt.html2.png";
- private const string colorShift1 = "../../../TestData/ColorShift1.png";
- private const string colorShift2 = "../../../TestData/ColorShift2.png";
-
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, png0Rgba32, true)]
- [TestCase(png0Rgba32, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, jpg1Rgb24, true)]
- [TestCase(png0Rgba32, pngBlack2x2px, false)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg1Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, false)]
public void ShouldVerifyThatImagesFromFilePathSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -37,11 +23,11 @@ public void ShouldVerifyThatImagesFromFilePathSizeAreEqual(string pathActual, st
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, png0Rgba32, true)]
- [TestCase(png0Rgba32, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, jpg1Rgb24, true)]
- [TestCase(png0Rgba32, pngBlack2x2px, false)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg1Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, false)]
public void ShouldVerifyThatImagesSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -54,11 +40,11 @@ public void ShouldVerifyThatImagesSizeAreEqual(string pathActual, string pathExp
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, png0Rgba32, true)]
- [TestCase(png0Rgba32, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, jpg1Rgb24, true)]
- [TestCase(png0Rgba32, pngBlack2x2px, false)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg1Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, false)]
public void ShouldVerifyThatImageStreamsSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -71,11 +57,11 @@ public void ShouldVerifyThatImageStreamsSizeAreEqual(string pathActual, string p
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(png0Rgba32, png0Rgba32, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg0Rgb24, jpg0Rgb24, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(png0Rgba32, png0Rgba32, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngTransparent2x2px, pngPartialTransparent2x2px, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngPartialTransparent2x2px, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
public void ShouldVerifyThatImagesAreEqual(string pathActual, string pathExpected, ResizeOption resizeOption, TransparencyOptions transparencyOptions)
{
var sut = new ImageCompare(resizeOption, transparencyOptions);
@@ -86,10 +72,10 @@ public void ShouldVerifyThatImagesAreEqual(string pathActual, string pathExpecte
}
[Test]
- [TestCase(pngBlack2x2px, pngBlack2x2px, ResizeOption.Resize, true)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, ResizeOption.Resize, true)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, ResizeOption.DontResize, false)]
- [TestCase(colorShift1, colorShift2, ResizeOption.DontResize, false)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, ResizeOption.Resize, true)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, ResizeOption.Resize, true)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, ResizeOption.DontResize, false)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, ResizeOption.DontResize, false)]
public void ShouldVerifyThatImagesWithDifferentSizeAreEqual(string pathActual, string pathExpected, ResizeOption resizeOption, bool expectedResult)
{
var sut = new ImageCompare(resizeOption);
@@ -100,8 +86,8 @@ public void ShouldVerifyThatImagesWithDifferentSizeAreEqual(string pathActual, s
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24)]
- [TestCase(png0Rgba32, png0Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
public void ShouldVerifyThatImageStreamsAreEqual(string pathActual, string pathExpected)
{
var sut = new ImageCompare();
@@ -115,8 +101,8 @@ public void ShouldVerifyThatImageStreamsAreEqual(string pathActual, string pathE
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24)]
- [TestCase(png0Rgba32, png0Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
public void ShouldVerifyThatSkiaSharpImagesAreEqual(string pathActual, string pathExpected)
{
var sut = new ImageCompare();
@@ -130,26 +116,26 @@ public void ShouldVerifyThatSkiaSharpImagesAreEqual(string pathActual, string pa
}
[Test]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg1Rgb24, png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg1Rgb24, png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(png0Rgba32, png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngBlack4x4px, pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(renderedForm1, renderedForm2, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(renderedForm2, renderedForm1, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(colorShift1, colorShift2, 117896, 3.437201166180758d, 30398, 88.623906705539355d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(colorShift1, colorShift2, 0, 0, 0, 0, ResizeOption.DontResize, 15, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngPartialTransparent2x2px, pngTransparent2x2px, 2048, 128.0d, 16, 100, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngPartialTransparent2x2px, pngTransparent2x2px, 0, 0, 0, 0, ResizeOption.DontResize, 0, TransparencyOptions.IgnoreAlphaChannel)]
- public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int pixelColorShiftTolerance, TransparencyOptions transparencyOptions)
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.png1Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.renderedForm1, TestFiles.renderedForm2, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.renderedForm2, TestFiles.renderedForm1, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 117896, 3.437201166180758d, 30398, 88.623906705539355d, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 0, 0, 0, 0, ResizeOption.DontResize, 15, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngPartialTransparent2x2px, TestFiles.pngTransparent2x2px, 2048, 128.0d, 16, 100, ResizeOption.DontResize, 0, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngPartialTransparent2x2px, TestFiles.pngTransparent2x2px, 0, 0, 0, 0, ResizeOption.DontResize, 0, TransparencyOptions.IgnoreAlphaChannel)]
+ public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int colorShiftTolerance, TransparencyOptions transparencyOptions)
{
- var sut = new ImageCompare(resizeOption, transparencyOptions, pixelColorShiftTolerance);
+ var sut = new ImageCompare(resizeOption, transparencyOptions, colorShiftTolerance);
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);
var diff = sut.CalcDiff(absolutePathPic1, absolutePathPic2);
@@ -165,8 +151,8 @@ public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2,
Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngBlack2x2px, pngBlack4x4px)]
- [TestCase(pngBlack4x4px, pngWhite2x2px)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px)]
public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1, string pathPic2)
{
var sut = new ImageCompare();
@@ -179,17 +165,17 @@ public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1,
}
[Test]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize)]
- [TestCase(jpg1Rgb24, png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize)]
- [TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize)]
- [TestCase(png0Rgba32, png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize)]
- [TestCase(pngBlack2x2px, pngWhite2x2px, 3060, 765, 4, 100.0d, ResizeOption.DontResize)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(pngBlack4x4px, pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.png1Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngWhite2x2px, 3060, 765, 4, 100.0d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize)]
public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var sut = new ImageCompare(resizeOption);
@@ -205,10 +191,10 @@ public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pat
Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngBlack2x2px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, true)]
- [TestCase(pngBlack2x2px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.DontResize, true)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, true)]
- [TestCase(pngBlack2x2px, pngWhite2x2px, 0, 0, 0, 0, ResizeOption.DontResize, false)]
+ [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)
{
var sut = new ImageCompare(resizeOption);
@@ -224,15 +210,15 @@ public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, int exp
}
}
- [TestCase(png0Rgba32, png1Rgba32, null, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngWhite2x2px, pngBlack2x2px, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngTransparent2x2px, pngPartialTransparent2x2px, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(png0Rgba32, png1Rgba32, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(png0Rgba32, png1Rgba32, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngWhite2x2px, pngBlack4x4px, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngBlack4x4px, pngWhite2x2px, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(renderedForm1, renderedForm2, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(renderedForm2, renderedForm1, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, null, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack2x2px, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngPartialTransparent2x2px, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack4x4px, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.renderedForm1, TestFiles.renderedForm2, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.renderedForm2, TestFiles.renderedForm1, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
public void CalcDiff(string pathPic1, string pathPic2, ResizeOption resizeOption, TransparencyOptions transparencyOptions)
{
var sut = new ImageCompare(resizeOption, transparencyOptions);
@@ -268,20 +254,20 @@ private static void SaveAsPng(SKBitmap maskImage, FileStream fileStreamDifferenc
encodedData.SaveTo(fileStreamDifferenceMask);
}
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngBlack2x2px, pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngTransparent2x2px, pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(pngTransparent2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngBlack2x2px, pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngTransparent2x2px, pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(pngTransparent2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, TransparencyOptions.IgnoreAlphaChannel)]
public void ShouldCalcDiffMaskSKBitmapAndUseOutcome(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, TransparencyOptions transparencyOptions)
{
var sut = new ImageCompare(resizeOption, transparencyOptions);
@@ -308,16 +294,16 @@ public void ShouldCalcDiffMaskSKBitmapAndUseOutcome(string pathPic1, string path
Assert.That(maskedDiff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngWhite2x2px, pngBlack2x2px, pngTransparent2x2px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
- [TestCase(pngWhite2x2px, pngBlack2x2px, pngBlack4x4px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
- [TestCase(pngBlack2x2px, pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(pngBlack4x4px, pngBlack2x2px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(colorShift1, colorShift1, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(colorShift1, colorShift2, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 20)]
- public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3, double expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int pixelColorShiftTolerance)
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack2x2px, TestFiles.pngTransparent2x2px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift1, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 20)]
+ public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3, double expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int colorShiftTolerance)
{
- var sut = new ImageCompare(resizeOption, TransparencyOptions.CompareAlphaChannel, pixelColorShiftTolerance);
+ var sut = new ImageCompare(resizeOption, TransparencyOptions.CompareAlphaChannel, colorShiftTolerance);
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);
var differenceMaskPic = Path.Combine(AppContext.BaseDirectory, pathPic3);
@@ -333,9 +319,9 @@ public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3,
Assert.That(maskedDiff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngBlack2x2px, pngBlack2x2px, pngBlack4x4px)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, pngBlack2x2px)]
- [TestCase(pngBlack4x4px, pngBlack2x2px, pngBlack2x2px)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px)]
public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, string pathPic2, string pathPic3)
{
var sut = new ImageCompare();
@@ -351,7 +337,7 @@ public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, stri
Assert.That(exception?.Message, Is.EqualTo("Size of images differ."));
}
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0)]
public void CalcDiffStreams(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage)
{
var sut = new ImageCompare(transparencyOptions: TransparencyOptions.IgnoreAlphaChannel);
@@ -373,15 +359,15 @@ public void CalcDiffStreams(string pathPic1, string pathPic2, int expectedMeanEr
Assert.That(maskedDiff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(png0Rgba32, png1Rgba32, TransparencyOptions.CompareAlphaChannel, 0)]
- [TestCase(colorShift1, colorShift2, TransparencyOptions.CompareAlphaChannel, 20)]
- [TestCase(png0Rgba32, png1Rgba32, TransparencyOptions.IgnoreAlphaChannel, 0)]
- [TestCase(colorShift1, colorShift2, TransparencyOptions.IgnoreAlphaChannel, 20)]
- [TestCase(pngTransparent2x2px, pngPartialTransparent2x2px, TransparencyOptions.IgnoreAlphaChannel, 0)]
- [TestCase(pngTransparent2x2px, pngPartialTransparent2x2px, TransparencyOptions.CompareAlphaChannel, 0)]
- public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDifferences(string image1RelativePath, string image2RelativePath, TransparencyOptions transparencyOptions, int pixelColorShiftTolerance)
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, TransparencyOptions.CompareAlphaChannel, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, TransparencyOptions.CompareAlphaChannel, 20)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, TransparencyOptions.IgnoreAlphaChannel, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, TransparencyOptions.IgnoreAlphaChannel, 20)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngPartialTransparent2x2px, TransparencyOptions.IgnoreAlphaChannel, 0)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngPartialTransparent2x2px, TransparencyOptions.CompareAlphaChannel, 0)]
+ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDifferences(string image1RelativePath, string image2RelativePath, TransparencyOptions transparencyOptions, int colorShiftTolerance)
{
- var sut = new ImageCompare(ResizeOption.DontResize, transparencyOptions, pixelColorShiftTolerance);
+ var sut = new ImageCompare(ResizeOption.DontResize, transparencyOptions, colorShiftTolerance);
var image1Path = Path.Combine(AppContext.BaseDirectory, image1RelativePath);
var image2Path = Path.Combine(AppContext.BaseDirectory, image2RelativePath);
var diffMask1Path = Path.GetTempFileName() + "differenceMask.png";
@@ -404,7 +390,7 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDiffe
File.Delete(diffMask1Path);
}
- [TestCase(png0Rgba32, png1Rgba32)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByStream_NoDifferences(string image1RelativePath, string image2RelativePath)
{
var sut = new ImageCompare();
@@ -434,7 +420,7 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByStream_NoDiffere
File.Delete(diffMask1Path);
}
- [TestCase(png0Rgba32, png1Rgba32)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByImage_NoDifferences(string image1RelativePath, string image2RelativePath)
{
var sut = new ImageCompare();
@@ -451,13 +437,13 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByImage_NoDifferen
}
[Test]
- [TestCase(jpg0Rgb24, jpg1Rgb24)]
- [TestCase(png0Rgba32, png1Rgba32)]
- [TestCase(jpg0Rgb24, png1Rgba32)]
- [TestCase(jpg0Rgb24, png0Rgba32)]
- [TestCase(jpg1Rgb24, png1Rgba32)]
- [TestCase(colorShift1, colorShift2)]
- [TestCase(pngTransparent2x2px, pngPartialTransparent2x2px)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngPartialTransparent2x2px)]
public void ShouldVerifyThatImagesAreNotEqual(string pathActual, string pathExpected)
{
var sut = new ImageCompare();
@@ -468,13 +454,13 @@ public void ShouldVerifyThatImagesAreNotEqual(string pathActual, string pathExpe
}
[Test]
- [TestCase(jpg0Rgb24, jpg1Rgb24)]
- [TestCase(png0Rgba32, png1Rgba32)]
- [TestCase(jpg0Rgb24, png1Rgba32)]
- [TestCase(jpg0Rgb24, png0Rgba32)]
- [TestCase(jpg1Rgb24, png1Rgba32)]
- [TestCase(colorShift1, colorShift2)]
- [TestCase(pngTransparent2x2px, pngPartialTransparent2x2px)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2)]
+ [TestCase(TestFiles.pngTransparent2x2px, TestFiles.pngPartialTransparent2x2px)]
public void ShouldVerifyThatImageStreamAreNotEqual(string pathActual, string pathExpected)
{
var sut = new ImageCompare();
@@ -487,8 +473,8 @@ public void ShouldVerifyThatImageStreamAreNotEqual(string pathActual, string pat
Assert.That(sut.ImagesAreEqual(actual, expected), Is.False);
}
- [TestCase(png0Rgba32, pngBlack2x2px, TransparencyOptions.IgnoreAlphaChannel)]
- [TestCase(png0Rgba32, pngBlack2x2px, TransparencyOptions.CompareAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, TransparencyOptions.IgnoreAlphaChannel)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, TransparencyOptions.CompareAlphaChannel)]
public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string pathPic2, TransparencyOptions transparencyOptions)
{
var sut = new ImageCompare(ResizeOption.DontResize, transparencyOptions);
@@ -500,11 +486,11 @@ public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string
Assert.That(exception?.Message, Is.EqualTo("Size of images differ."));
}
- [TestCase(png0Rgba32, png0Rgba32, pngBlack2x2px)]
- [TestCase(png0Rgba32, pngBlack2x2px, png0Rgba32)]
- [TestCase(pngBlack2x2px, png0Rgba32, png0Rgba32)]
- [TestCase(pngPartialTransparent2x2px, png0Rgba32, png0Rgba32)]
- [TestCase(png0Rgba32, png0Rgba32, pngPartialTransparent2x2px)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, TestFiles.pngBlack2x2px)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.pngPartialTransparent2x2px, TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, TestFiles.pngPartialTransparent2x2px)]
public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string pathPic2, string pathPic3)
{
var sut = new ImageCompare();
diff --git a/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs b/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs
index 31e7182..730a416 100644
--- a/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs
+++ b/SkiaSharpCompareTestNunit/SkiaSharpStaticCompareTests.cs
@@ -8,25 +8,12 @@ namespace SkiaSharpCompareTestNunit
{
public class SkiaSharpStaticCompareTests
{
- private const string jpg0Rgb24 = "../../../TestData/Calc0.jpg";
- private const string jpg1Rgb24 = "../../../TestData/Calc1.jpg";
- private const string png0Rgba32 = "../../../TestData/Calc0.png";
- private const string png1Rgba32 = "../../../TestData/Calc1.png";
- private const string pngBlack2x2px = "../../../TestData/Black.png";
- private const string pngBlack4x4px = "../../../TestData/BlackDoubleSize.png";
- private const string pngWhite2x2px = "../../../TestData/White.png";
- private const string pngTransparent2x2px = "../../../TestData/pngTransparent2x2px.png";
- private const string renderedForm1 = "../../../TestData/HC007-Test-02-3-OxPt.html1.png";
- private const string renderedForm2 = "../../../TestData/HC007-Test-02-3-OxPt.html2.png";
- private const string colorShift1 = "../../../TestData/ColorShift1.png";
- private const string colorShift2 = "../../../TestData/ColorShift2.png";
-
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, png0Rgba32, true)]
- [TestCase(png0Rgba32, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, jpg1Rgb24, true)]
- [TestCase(png0Rgba32, pngBlack2x2px, false)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg1Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, false)]
public void ShouldVerifyThatImagesFromFilePathSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -36,11 +23,11 @@ public void ShouldVerifyThatImagesFromFilePathSizeAreEqual(string pathActual, st
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, png0Rgba32, true)]
- [TestCase(png0Rgba32, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, jpg1Rgb24, true)]
- [TestCase(png0Rgba32, pngBlack2x2px, false)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg1Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, false)]
public void ShouldVerifyThatImagesSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -53,11 +40,11 @@ public void ShouldVerifyThatImagesSizeAreEqual(string pathActual, string pathExp
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, png0Rgba32, true)]
- [TestCase(png0Rgba32, jpg0Rgb24, true)]
- [TestCase(png0Rgba32, jpg1Rgb24, true)]
- [TestCase(png0Rgba32, pngBlack2x2px, false)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg0Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.jpg1Rgb24, true)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, false)]
public void ShouldVerifyThatImageStreamsSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -70,22 +57,22 @@ public void ShouldVerifyThatImageStreamsSizeAreEqual(string pathActual, string p
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24, 0)]
- [TestCase(png0Rgba32, png0Rgba32, 0)]
- [TestCase(colorShift1, colorShift2, 15)]
- public void ShouldVerifyThatImagesAreEqual(string pathActual, string pathExpected, int pixelColorShiftTolerance)
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24, 0)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 15)]
+ public void ShouldVerifyThatImagesAreEqual(string pathActual, string pathExpected, int colorShiftTolerance)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
var absolutePathExpected = Path.Combine(AppContext.BaseDirectory, pathExpected);
- Assert.That(Compare.ImagesAreEqual(absolutePathActual, absolutePathExpected, pixelColorShiftTolerance: pixelColorShiftTolerance), Is.True);
+ Assert.That(Compare.ImagesAreEqual(absolutePathActual, absolutePathExpected, pixelColorShiftTolerance: colorShiftTolerance), Is.True);
}
[Test]
- [TestCase(pngBlack2x2px, pngBlack2x2px, ResizeOption.Resize, true)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, ResizeOption.Resize, true)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, ResizeOption.DontResize, false)]
- [TestCase(colorShift1, colorShift2, ResizeOption.DontResize, false)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, ResizeOption.Resize, true)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, ResizeOption.Resize, true)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, ResizeOption.DontResize, false)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, ResizeOption.DontResize, false)]
public void ShouldVerifyThatImagesWithDifferentSizeAreEqual(string pathActual, string pathExpected, ResizeOption resizeOption, bool expectedResult)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -95,8 +82,8 @@ public void ShouldVerifyThatImagesWithDifferentSizeAreEqual(string pathActual, s
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24)]
- [TestCase(png0Rgba32, png0Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
public void ShouldVerifyThatImageStreamsAreEqual(string pathActual, string pathExpected)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -109,8 +96,8 @@ public void ShouldVerifyThatImageStreamsAreEqual(string pathActual, string pathE
}
[Test]
- [TestCase(jpg0Rgb24, jpg0Rgb24)]
- [TestCase(png0Rgba32, png0Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg0Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
public void ShouldVerifyThatSkiaSharpImagesAreEqual(string pathActual, string pathExpected)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -123,26 +110,26 @@ public void ShouldVerifyThatSkiaSharpImagesAreEqual(string pathActual, string pa
}
[Test]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null, 0)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize, 0)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize, 0)]
- [TestCase(jpg1Rgb24, png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0)]
- [TestCase(jpg1Rgb24, png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0)]
- [TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, 0)]
- [TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, 0)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize, 0)]
- [TestCase(png0Rgba32, png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize, 0)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(pngBlack4x4px, pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize, 0)]
- [TestCase(renderedForm1, renderedForm2, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0)]
- [TestCase(renderedForm2, renderedForm1, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0)]
- [TestCase(colorShift1, colorShift2, 117896, 3.437201166180758d, 30398, 88.623906705539355d, ResizeOption.DontResize, 0)]
- [TestCase(colorShift1, colorShift2, 0, 0, 0, 0, ResizeOption.DontResize, 15)]
- public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int pixelColorShiftTolerance)
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null, 0)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.png1Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.renderedForm1, TestFiles.renderedForm2, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.renderedForm2, TestFiles.renderedForm1, 49267623, 60.794204096742348d, 174178, 21.49284304047384d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 117896, 3.437201166180758d, 30398, 88.623906705539355d, ResizeOption.DontResize, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 0, 0, 0, 0, ResizeOption.DontResize, 15)]
+ public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int colorShiftTolerance)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);
- var diff = Compare.CalcDiff(absolutePathPic1, absolutePathPic2, resizeOption, pixelColorShiftTolerance);
+ var diff = Compare.CalcDiff(absolutePathPic1, absolutePathPic2, resizeOption, colorShiftTolerance);
Console.WriteLine($"PixelErrorCount: {diff.PixelErrorCount}");
Console.WriteLine($"PixelErrorPercentage: {diff.PixelErrorPercentage}");
@@ -155,8 +142,8 @@ public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2,
Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngBlack2x2px, pngBlack4x4px)]
- [TestCase(pngBlack4x4px, pngWhite2x2px)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px)]
public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1, string pathPic2)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -169,17 +156,17 @@ public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1,
}
[Test]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize)]
- [TestCase(jpg0Rgb24, png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize)]
- [TestCase(jpg1Rgb24, png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize)]
- [TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize)]
- [TestCase(png0Rgba32, png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize)]
- [TestCase(pngBlack2x2px, pngWhite2x2px, 3060, 765, 4, 100.0d, ResizeOption.DontResize)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(pngBlack4x4px, pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, null)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32, 461891, 2.8574583652965777d, 158087, 97.799485288659028d, ResizeOption.Resize)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32, 460034, 2.8459701566405187d, 158121, 97.820519165573728d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.png1Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 208890, 1.2922842790329365d, 2101, 1.2997698646408156d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngWhite2x2px, 3060, 765, 4, 100.0d, ResizeOption.DontResize)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px, 12240, 765, 16, 100.0d, ResizeOption.Resize)]
public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -194,13 +181,13 @@ public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pat
Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0, null)]
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(pngWhite2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(pngBlack4x4px, pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(renderedForm1, renderedForm2, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(renderedForm2, renderedForm1, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, null)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngWhite2x2px, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.renderedForm1, TestFiles.renderedForm2, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.renderedForm2, TestFiles.renderedForm1, 0, 0, 0, 0, ResizeOption.Resize)]
public void DiffMask(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -228,9 +215,9 @@ private static void SaveAsPng(SKBitmap maskImage, FileStream fileStreamDifferenc
encodedData.SaveTo(fileStreamDifferenceMask);
}
- [TestCase(pngBlack2x2px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(pngBlack2x2px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
+ [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)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -245,10 +232,10 @@ public void ShouldCalcDiffMaskSKBitmap(string pathPic1, string pathPic2, int exp
}
}
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
- [TestCase(jpg0Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.Resize)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24, 0, 0, 0, 0, ResizeOption.Resize)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize)]
public void ShouldCalcDiffMaskSKBitmapAndUseOutcome(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -274,14 +261,14 @@ public void ShouldCalcDiffMaskSKBitmapAndUseOutcome(string pathPic1, string path
Assert.That(maskedDiff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngWhite2x2px, pngBlack2x2px, pngTransparent2x2px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
- [TestCase(pngWhite2x2px, pngBlack2x2px, pngBlack4x4px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
- [TestCase(pngBlack2x2px, pngBlack2x2px, pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(pngBlack4x4px, pngBlack2x2px, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(colorShift1, colorShift1, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
- [TestCase(colorShift1, colorShift2, pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 20)]
- public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3, double expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int pixelColorShiftTolerance)
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack2x2px, TestFiles.pngTransparent2x2px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngWhite2x2px, TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 765, 12240, 16, 100d, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift1, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 0)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, TestFiles.pngBlack2x2px, 0, 0, 0, 0, ResizeOption.Resize, 20)]
+ public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3, double expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption, int colorShiftTolerance)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);
@@ -290,7 +277,7 @@ public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3,
using var pic2 = SKBitmap.Decode(absolutePathPic2);
using var maskPic = SKBitmap.Decode(differenceMaskPic);
- var maskedDiff = Compare.CalcDiff(pic1, pic2, maskPic, resizeOption, pixelColorShiftTolerance);
+ var maskedDiff = Compare.CalcDiff(pic1, pic2, maskPic, resizeOption, colorShiftTolerance);
Assert.That(maskedDiff.MeanError, Is.EqualTo(expectedMeanError), "MeanError");
Assert.That(maskedDiff.AbsoluteError, Is.EqualTo(expectedAbsoluteError), "AbsoluteError");
@@ -298,9 +285,9 @@ public void ShouldUseDiffMask(string pathPic1, string pathPic2, string pathPic3,
Assert.That(maskedDiff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(pngBlack2x2px, pngBlack2x2px, pngBlack4x4px)]
- [TestCase(pngBlack2x2px, pngBlack4x4px, pngBlack2x2px)]
- [TestCase(pngBlack4x4px, pngBlack2x2px, pngBlack2x2px)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px)]
+ [TestCase(TestFiles.pngBlack4x4px, TestFiles.pngBlack2x2px, TestFiles.pngBlack2x2px)]
public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, string pathPic2, string pathPic3)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -315,7 +302,7 @@ public void ShouldThrowUsingInvalidImageDimensionsDiffMask(string pathPic1, stri
Assert.That(exception?.Message, Is.EqualTo("Size of images differ."));
}
- [TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, 0, 0, 0)]
public void DiffMaskStreams(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -336,10 +323,10 @@ public void DiffMaskStreams(string pathPic1, string pathPic2, int expectedMeanEr
Assert.That(maskedDiff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}
- [TestCase(png0Rgba32, png1Rgba32, 0, false)]
- [TestCase(colorShift1, colorShift2, 20, true)]
- [TestCase(colorShift1, colorShift2, 0, false)]
- public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDifferences(string image1RelativePath, string image2RelativePath, int pixelColorShiftTolerance, bool expectIsImageEntirelyBlack)
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, 0, false)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 20, true)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 0, false)]
+ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDifferences(string image1RelativePath, string image2RelativePath, int colorShiftTolerance, bool expectIsImageEntirelyBlack)
{
var image1Path = Path.Combine(AppContext.BaseDirectory, image1RelativePath);
var image2Path = Path.Combine(AppContext.BaseDirectory, image2RelativePath);
@@ -347,7 +334,7 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDiffe
using (var diffMask1Stream = File.Create(diffMask1Path))
{
- using var diffMask1Image = Compare.CalcDiffMaskImage(image1Path, image2Path, ResizeOption.DontResize, pixelColorShiftTolerance);
+ using var diffMask1Image = Compare.CalcDiffMaskImage(image1Path, image2Path, ResizeOption.DontResize, colorShiftTolerance);
ImageExtensions.SaveAsPng(diffMask1Image, diffMask1Stream);
Assert.That(ImageExtensions.IsImageEntirelyBlack(diffMask1Image, TransparencyOptions.IgnoreAlphaChannel), Is.EqualTo(expectIsImageEntirelyBlack));
}
@@ -364,7 +351,7 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByFilePath_NoDiffe
File.Delete(diffMask1Path);
}
- [TestCase(png0Rgba32, png1Rgba32)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByStream_NoDifferences(string image1RelativePath, string image2RelativePath)
{
var image1Path = Path.Combine(AppContext.BaseDirectory, image1RelativePath);
@@ -393,9 +380,9 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByStream_NoDiffere
File.Delete(diffMask1Path);
}
- [TestCase(png0Rgba32, png1Rgba32, png1Rgba32, 0, false)]
- [TestCase(colorShift1, colorShift1, colorShift2, 15, true)]
- public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByImage_NoDifferences(string image1RelativePath, string image2RelativePath, string image3RelativePath, int expectedPixelColorShiftTolerance, bool expectToleranceMaskToEntirelyBlack)
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32, TestFiles.png1Rgba32, 0, false)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift1, TestFiles.colorShift2, 15, true)]
+ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByImage_NoDifferences(string image1RelativePath, string image2RelativePath, string image3RelativePath, int colorShiftTolerance, bool expectToleranceMaskToEntirelyBlack)
{
var image1Path = Path.Combine(AppContext.BaseDirectory, image1RelativePath);
var image2Path = Path.Combine(AppContext.BaseDirectory, image2RelativePath);
@@ -407,16 +394,16 @@ public void CalcDiffMaskImage_WhenSupplyingDiffMaskOfTwoImagesByImage_NoDifferen
using var diffMask1Image = Compare.CalcDiffMaskImage(image1, image2);
- using var diffMask2Image = Compare.CalcDiffMaskImage(image1, image3, diffMask1Image, pixelColorShiftTolerance: expectedPixelColorShiftTolerance);
+ using var diffMask2Image = Compare.CalcDiffMaskImage(image1, image3, diffMask1Image, pixelColorShiftTolerance: colorShiftTolerance);
Assert.That(ImageExtensions.IsImageEntirelyBlack(diffMask1Image, TransparencyOptions.IgnoreAlphaChannel), Is.EqualTo(expectToleranceMaskToEntirelyBlack));
Assert.That(ImageExtensions.IsImageEntirelyBlack(diffMask2Image, TransparencyOptions.IgnoreAlphaChannel), Is.True);
}
- [TestCase(png0Rgba32, png0Rgba32, 0)]
- [TestCase(png0Rgba32, png0Rgba32, 15)]
- [TestCase(colorShift1, colorShift2, 15)]
- public void CalcDiffMaskImage_ToleranceColorShift_NoDifferences(string image1RelativePath, string image2RelativePath, int expectedPixelColorShiftTolerance)
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, 0)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, 15)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2, 15)]
+ public void CalcDiffMaskImage_ToleranceColorShift_NoDifferences(string image1RelativePath, string image2RelativePath, int colorShiftTolerance)
{
var image1Path = Path.Combine(AppContext.BaseDirectory, image1RelativePath);
var image2Path = Path.Combine(AppContext.BaseDirectory, image2RelativePath);
@@ -424,18 +411,18 @@ public void CalcDiffMaskImage_ToleranceColorShift_NoDifferences(string image1Rel
using var image1 = SKBitmap.Decode(image1Path);
using var image2 = SKBitmap.Decode(image2Path);
- using var diffMask1Image = Compare.CalcDiffMaskImage(image1, image2, pixelColorShiftTolerance: expectedPixelColorShiftTolerance);
+ using var diffMask1Image = Compare.CalcDiffMaskImage(image1, image2, pixelColorShiftTolerance: colorShiftTolerance);
Assert.That(ImageExtensions.IsImageEntirelyBlack(diffMask1Image, TransparencyOptions.IgnoreAlphaChannel), Is.True);
}
[Test]
- [TestCase(jpg0Rgb24, jpg1Rgb24)]
- [TestCase(png0Rgba32, png1Rgba32)]
- [TestCase(jpg0Rgb24, png1Rgba32)]
- [TestCase(jpg0Rgb24, png0Rgba32)]
- [TestCase(jpg1Rgb24, png1Rgba32)]
- [TestCase(colorShift1, colorShift2)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2)]
public void ShouldVerifyThatImagesAreNotEqual(string pathActual, string pathExpected)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -445,12 +432,12 @@ public void ShouldVerifyThatImagesAreNotEqual(string pathActual, string pathExpe
}
[Test]
- [TestCase(jpg0Rgb24, jpg1Rgb24)]
- [TestCase(png0Rgba32, png1Rgba32)]
- [TestCase(jpg0Rgb24, png1Rgba32)]
- [TestCase(jpg0Rgb24, png0Rgba32)]
- [TestCase(jpg1Rgb24, png1Rgba32)]
- [TestCase(colorShift1, colorShift2)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.jpg1Rgb24)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.jpg0Rgb24, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.jpg1Rgb24, TestFiles.png1Rgba32)]
+ [TestCase(TestFiles.colorShift1, TestFiles.colorShift2)]
public void ShouldVerifyThatImageStreamAreNotEqual(string pathActual, string pathExpected)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
@@ -462,7 +449,7 @@ public void ShouldVerifyThatImageStreamAreNotEqual(string pathActual, string pat
Assert.That(Compare.ImagesAreEqual(actual, expected), Is.False);
}
- [TestCase(png0Rgba32, pngBlack2x2px)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px)]
public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string pathPic2)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
@@ -473,9 +460,9 @@ public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string
Assert.That(exception?.Message, Is.EqualTo("Size of images differ."));
}
- [TestCase(png0Rgba32, png0Rgba32, pngBlack2x2px)]
- [TestCase(png0Rgba32, pngBlack2x2px, png0Rgba32)]
- [TestCase(pngBlack2x2px, png0Rgba32, png0Rgba32)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.png0Rgba32, TestFiles.pngBlack2x2px)]
+ [TestCase(TestFiles.png0Rgba32, TestFiles.pngBlack2x2px, TestFiles.png0Rgba32)]
+ [TestCase(TestFiles.pngBlack2x2px, TestFiles.png0Rgba32, TestFiles.png0Rgba32)]
public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string pathPic2, string pathPic3)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
diff --git a/SkiaSharpCompareTestNunit/TestData/imageWithGpsMetadata.jpg b/SkiaSharpCompareTestNunit/TestData/imageWithGpsMetadata.jpg
new file mode 100644
index 0000000..4e4c0ff
Binary files /dev/null and b/SkiaSharpCompareTestNunit/TestData/imageWithGpsMetadata.jpg differ
diff --git a/SkiaSharpCompareTestNunit/TestData/imageWithoutGpsMetadata.jpg b/SkiaSharpCompareTestNunit/TestData/imageWithoutGpsMetadata.jpg
new file mode 100644
index 0000000..1313728
Binary files /dev/null and b/SkiaSharpCompareTestNunit/TestData/imageWithoutGpsMetadata.jpg differ
diff --git a/SkiaSharpCompareTestNunit/TestFiles.cs b/SkiaSharpCompareTestNunit/TestFiles.cs
new file mode 100644
index 0000000..4471bc1
--- /dev/null
+++ b/SkiaSharpCompareTestNunit/TestFiles.cs
@@ -0,0 +1,24 @@
+namespace SkiaSharpCompareTestNunit
+{
+ internal static class TestFiles
+ {
+ public const string jpg0Rgb24 = "./../../../TestData/Calc0.jpg";
+ public const string jpg1Rgb24 = "./../../../TestData/Calc1.jpg";
+ public const string png0Rgba32 = "./../../../TestData/Calc0.png";
+ public const string png1Rgba32 = "./../../../TestData/Calc1.png";
+ public const string pngBlack2x2px = "./../../../TestData/Black.png";
+ public const string pngBlack4x4px = "./../../../TestData/BlackDoubleSize.png";
+ public const string pngWhite2x2px = "./../../../TestData/White.png";
+ public const string pngTransparent2x2px = "./../../../TestData/pngTransparent2x2px.png";
+ public const string pngPartialTransparent2x2px = "./../../../TestData/pngPartialTransparent2x2px.png";
+ public const string renderedForm1 = "./../../../TestData/HC007-Test-02-3-OxPt.html1.png";
+ public const string renderedForm2 = "./../../../TestData/HC007-Test-02-3-OxPt.html2.png";
+ public const string colorShift1 = "./../../../TestData/ColorShift1.png";
+ public const string colorShift2 = "./../../../TestData/ColorShift2.png";
+
+ // These changes are related to https://github.com/nextcloud/android/issues/6248#issuecomment-1207315271
+ public const string imageWithoutGpsMetadata = "./../../../TestData/imageWithoutGpsMetadata.jpg";
+
+ public const string imageWithGpsMetadata = "./../../../TestData/imageWithGpsMetadata.jpg";
+ }
+}
\ No newline at end of file