Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: dotnet test --no-build --verbosity normal --configuration Release

deployRelease:
if: github.ref == 'refs/heads/release'
if: startsWith(github.ref, 'refs/heads/release')
runs-on: ubuntu-latest
needs: build
steps:
Expand Down
1 change: 0 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"recommendations": [
"mhutchie.git-graph",
"streetsidesoftware.code-spell-checker",
"slevesque.vscode-hexdump",
"timonwong.shellcheck",
"redhat.vscode-xml",
"redhat.vscode-yaml"
Expand Down
151 changes: 114 additions & 37 deletions ImageSharpCompare/ImageSharpCompare.cs

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions ImageSharpCompare/ResizeOption.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Codeuctivity.ImageSharpCompare
{
/// <summary>
/// Options that are applied if images do have different image dimension
/// </summary>
public enum ResizeOption
{
/// <summary>
/// Dont resize images with different size.
/// </summary>
DontResize,

/// <summary>
/// Images with different size will get resized before pixel based compare is used to determine equality.
/// </summary>
Resize
}
}
93 changes: 65 additions & 28 deletions ImageSharpCompareTestNunit/ImageSharpCompareTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ public class IntegrationTest
private const string jpg1Rgb24 = "../../../TestData/Calc1.jpg";
private const string png0Rgba32 = "../../../TestData/Calc0.png";
private const string png1Rgba32 = "../../../TestData/Calc1.png";
private const string pngBlack = "../../../TestData/Black.png";
private const string pngWhite = "../../../TestData/White.png";
private const string pngBlack2x2px = "../../../TestData/Black.png";
private const string pngBlack4x4px = "../../../TestData/BlackDoubleSize.png";
private const string pngWhite2x2px = "../../../TestData/White.png";

[Test]
[TestCase(jpg0Rgb24, jpg0Rgb24, true)]
[TestCase(png0Rgba32, png0Rgba32, true)]
[TestCase(png0Rgba32, jpg0Rgb24, true)]
[TestCase(png0Rgba32, jpg1Rgb24, true)]
[TestCase(png0Rgba32, pngBlack, false)]
[TestCase(png0Rgba32, pngBlack2x2px, false)]
public void ShouldVerifyThatImagesFromFilepathSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
Expand All @@ -35,7 +36,7 @@ public void ShouldVerifyThatImagesFromFilepathSizeAreEqual(string pathActual, st
[TestCase(png0Rgba32, png0Rgba32, true)]
[TestCase(png0Rgba32, jpg0Rgb24, true)]
[TestCase(png0Rgba32, jpg1Rgb24, true)]
[TestCase(png0Rgba32, pngBlack, false)]
[TestCase(png0Rgba32, pngBlack2x2px, false)]
public void ShouldVerifyThatImagesSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
Expand All @@ -52,7 +53,7 @@ public void ShouldVerifyThatImagesSizeAreEqual(string pathActual, string pathExp
[TestCase(png0Rgba32, png0Rgba32, true)]
[TestCase(png0Rgba32, jpg0Rgb24, true)]
[TestCase(png0Rgba32, jpg1Rgb24, true)]
[TestCase(png0Rgba32, pngBlack, false)]
[TestCase(png0Rgba32, pngBlack2x2px, false)]
public void ShouldVerifyThatImageStreamsSizeAreEqual(string pathActual, string pathExpected, bool expectedOutcome)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
Expand All @@ -75,6 +76,18 @@ public void ShouldVerifyThatImagesAreEqual(string pathActual, string pathExpecte
Assert.That(ImageSharpCompare.ImagesAreEqual(absolutePathActual, absolutePathExpected), Is.True);
}

[Test]
[TestCase(pngBlack2x2px, pngBlack2x2px, ResizeOption.Resize, true)]
[TestCase(pngBlack2x2px, pngBlack4x4px, ResizeOption.Resize, true)]
[TestCase(pngBlack2x2px, pngBlack4x4px, ResizeOption.DontResize, false)]
public void ShouldVerifyThatImagesWithDifferentSizeAreEqual(string pathActual, string pathExpected, ResizeOption resizeOption, bool expectedResult)
{
var absolutePathActual = Path.Combine(AppContext.BaseDirectory, pathActual);
var absolutePathExpected = Path.Combine(AppContext.BaseDirectory, pathExpected);

Assert.That(ImageSharpCompare.ImagesAreEqual(absolutePathActual, absolutePathExpected, resizeOption), Is.EqualTo(expectedResult));
}

[Test]
[TestCase(jpg0Rgb24, jpg0Rgb24)]
[TestCase(png0Rgba32, png0Rgba32)]
Expand Down Expand Up @@ -106,19 +119,23 @@ public void ShouldVerifyThatImageSharpImagesAreEqual(string pathActual, string p
}

[Test]
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d)]
[TestCase(jpg1Rgb24, png1Rgba32, 382669, 2.3673566603152607d, 140893, 87.162530004206772d)]
[TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0)]
[TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0)]
[TestCase(jpg0Rgb24, jpg1Rgb24, 208832, 1.2919254658385093d, 2089, 1.2923461433768035d)]
[TestCase(png0Rgba32, png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d)]
[TestCase(pngBlack, pngWhite, 3060, 765, 4, 100.0d)]
public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage)
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d, null)]
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d, ResizeOption.DontResize)]
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d, ResizeOption.Resize)]
[TestCase(jpg1Rgb24, png1Rgba32, 382669, 2.3673566603152607d, 140893, 87.162530004206772d, ResizeOption.DontResize)]
[TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
[TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
[TestCase(jpg0Rgb24, jpg1Rgb24, 208832, 1.2919254658385093d, 2089, 1.2923461433768035d, 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)]
public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);

var diff = ImageSharpCompare.CalcDiff(absolutePathPic1, absolutePathPic2);
var diff = ImageSharpCompare.CalcDiff(absolutePathPic1, absolutePathPic2, resizeOption);

Console.WriteLine($"PixelErrorCount: {diff.PixelErrorCount}");
Console.WriteLine($"PixelErrorPercentage: {diff.PixelErrorPercentage}");
Expand All @@ -131,43 +148,63 @@ public void ShouldVerifyThatImagesAreSemiEqual(string pathPic1, string pathPic2,
Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}

[TestCase(pngBlack2x2px, pngBlack4x4px)]
[TestCase(pngBlack4x4px, pngWhite2x2px)]
public void ShouldVerifyThatCalcDiffThrowsOnDifferentImageSizes(string pathPic1, string pathPic2)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);

var exception = Assert.Throws<ImageSharpCompareException>(
() => ImageSharpCompare.CalcDiff(absolutePathPic1, absolutePathPic2, ResizeOption.DontResize));

Assert.That(exception?.Message, Is.EqualTo("Size of images differ."));
}

[Test]
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d)]
[TestCase(jpg1Rgb24, png1Rgba32, 382669, 2.3673566603152607d, 140893, 87.162530004206772d)]
[TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0)]
[TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0)]
[TestCase(jpg0Rgb24, jpg1Rgb24, 208832, 1.2919254658385093d, 2089, 1.2923461433768035d)]
[TestCase(png0Rgba32, png1Rgba32, 203027, 1.25601321422385d, 681, 0.42129618173269651d)]
[TestCase(pngBlack, pngWhite, 3060, 765, 4, 100.0d)]
public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage)
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d, null)]
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d, ResizeOption.DontResize)]
[TestCase(jpg0Rgb24, png0Rgba32, 384538, 2.3789191061839596d, 140855, 87.139021553537404d, ResizeOption.Resize)]
[TestCase(jpg1Rgb24, png1Rgba32, 382669, 2.3673566603152607d, 140893, 87.162530004206772d, ResizeOption.DontResize)]
[TestCase(png1Rgba32, png1Rgba32, 0, 0, 0, 0, ResizeOption.DontResize)]
[TestCase(jpg1Rgb24, jpg1Rgb24, 0, 0, 0, 0, ResizeOption.DontResize)]
[TestCase(jpg0Rgb24, jpg1Rgb24, 208832, 1.2919254658385093d, 2089, 1.2923461433768035d, 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)]
public void ShouldVerifyThatImageStreamsAreSemiEqual(string pathPic1, string pathPic2, int expectedAbsoluteError, double expectedMeanError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);

using var pic1 = new FileStream(absolutePathPic1, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var pic2 = new FileStream(absolutePathPic2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

var diff = ImageSharpCompare.CalcDiff(pic1, pic2);
var diff = ImageSharpCompare.CalcDiff(pic1, pic2, resizeOption);
Assert.That(diff.AbsoluteError, Is.EqualTo(expectedAbsoluteError), "AbsoluteError");
Assert.That(diff.MeanError, Is.EqualTo(expectedMeanError), "MeanError");
Assert.That(diff.PixelErrorCount, Is.EqualTo(expectedPixelErrorCount), "PixelErrorCount");
Assert.That(diff.PixelErrorPercentage, Is.EqualTo(expectedPixelErrorPercentage), "PixelErrorPercentage");
}

[TestCase(png0Rgba32, png1Rgba32, 0, 0, 0, 0)]
public void ShoulCalcDiffmask(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage)
[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)]
public void Diffmask(string pathPic1, string pathPic2, int expectedMeanError, int expectedAbsoluteError, int expectedPixelErrorCount, double expectedPixelErrorPercentage, ResizeOption resizeOption)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
var absolutePathPic2 = Path.Combine(AppContext.BaseDirectory, pathPic2);
var differenceMask = Path.GetTempFileName() + "differenceMask.png";

using (var fileStreamDifferenceMask = File.Create(differenceMask))
using (var maskImage = ImageSharpCompare.CalcDiffMaskImage(absolutePathPic1, absolutePathPic2))
using (var maskImage = ImageSharpCompare.CalcDiffMaskImage(absolutePathPic1, absolutePathPic2, resizeOption))
{
ImageExtensions.SaveAsPng(maskImage, fileStreamDifferenceMask);
}

var maskedDiff = ImageSharpCompare.CalcDiff(absolutePathPic1, absolutePathPic2, differenceMask);
var maskedDiff = ImageSharpCompare.CalcDiff(absolutePathPic1, absolutePathPic2, differenceMask, resizeOption);
File.Delete(differenceMask);

Assert.That(maskedDiff.AbsoluteError, Is.EqualTo(expectedAbsoluteError), "AbsoluteError");
Expand Down Expand Up @@ -281,7 +318,7 @@ public void ShouldVerifyThatImageStreamAreNotEqual(string pathActual, string pat
Assert.That(ImageSharpCompare.ImagesAreEqual(actual, expected), Is.False);
}

[TestCase(png0Rgba32, pngBlack)]
[TestCase(png0Rgba32, pngBlack2x2px)]
public void ShouldVerifyThatImageWithDifferentSizeThrows(string pathPic1, string pathPic2)
{
var absolutePathPic1 = Path.Combine(AppContext.BaseDirectory, pathPic1);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ ImageSharpCompare focus on os agnostic support and therefore depends on [SixLabo

## Example simple show cases

### Compares each RGB value of each pixel to determine the equality

```csharp
bool isEqual = ImageSharpCompare.ImagesAreEqual("actual.png", "expected.png");
```

### Calculates diff

```csharp
var calcDiff = ImageSharpCompare.CalcDiff("2x2PixelBlack.png", "2x2PixelWhite.png");
Console.WriteLine($"PixelErrorCount: {diff.PixelErrorCount}");
Console.WriteLine($"PixelErrorPercentage: {diff.PixelErrorPercentage}");
Expand All @@ -40,7 +46,7 @@ Imagine two images you want to compare, and want to accept the found difference

### Tolerance mask image

using "compare.CalcDiff" you can calc a diff mask from actual and reference image
Using **CalcDiffMaskImage** you can calc a diff mask from actual and reference image

Example - Create difference image

Expand All @@ -58,7 +64,3 @@ Example - Compare two images using the created difference image. Add white pixel
var maskedDiff = ImageSharpCompare.CalcDiff(pathPic1, pathPic2, "differenceMask.png");
Assert.That(maskedDiff.AbsoluteError, Is.EqualTo(0));
```

## .net Framework specific note

.net framework (an older Windows-based .NET implementation) is supported by versions 2.x.y .