Skip to content

Commit 43787d2

Browse files
Merge pull request #106 from aquality-automation/feature/cross-platform-visualization
[Visual] Migration from System.Drawing.Common to SkiaSharp +semver: breaking
2 parents 133a0d3 + 4541f8c commit 43787d2

File tree

15 files changed

+198
-124
lines changed

15 files changed

+198
-124
lines changed

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Aquality.Selenium.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
<PackageReference Include="NLog" Version="5.1.2" />
5454
<PackageReference Include="Selenium.Support" Version="4.8.1" />
5555
<PackageReference Include="Selenium.WebDriver" Version="4.8.1" />
56-
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
56+
<PackageReference Include="SkiaSharp" Version="2.88.3" />
5757
</ItemGroup>
5858
</Project>

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Aquality.Selenium.Core.xml

Lines changed: 30 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Resources/Localization/uk.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"loc.form.dump.exceededdumpname": "Перевищено довжину назви дампу. Кінцевий шлях: [{0}]",
3333
"loc.form.dump.imagenotsaved": "Не вдалося зберегти зображення елемента [{0}]: {1}",
3434
"loc.form.dump.compare": "Порівняння елементів форми з дампом [{0}]",
35-
"loc.form.dump.elementnotfound": "Елемент [{0}]знайдено в дампі, але не знайдено на формі",
35+
"loc.form.dump.elementnotfound": "Елемент [{0}] знайдено в дампі, але не знайдено на формі",
3636
"loc.form.dump.elementsmissedindump": "Елементи, які були знайдені на формі, але пропущені в дампі: [{0}].",
3737
"loc.form.dump.elementsmissedonform": "Елементи, які були знайдені в дампі, але пропущені на формі: [{0}].",
3838
"loc.form.dump.unprocessedelements": "Кількість необроблених (без відповідності між формою і дампом) елементів становить [{0}]. Для них різниця вважається 100%",

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Visualization/DumpManager.cs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Aquality.Selenium.Core.Localization;
44
using System;
55
using System.Collections.Generic;
6-
using System.Drawing;
76
using System.Globalization;
87
using System.IO;
98
using System.Linq;
@@ -39,15 +38,7 @@ public virtual float Compare(string dumpName = null)
3938
{
4039
var directory = GetDumpDirectory(dumpName);
4140
LocalizedLogger.Info("loc.form.dump.compare", directory.Name);
42-
if (!directory.Exists)
43-
{
44-
throw new InvalidOperationException($"Dump directory [{directory.FullName}] does not exist.");
45-
}
46-
var imageFiles = directory.GetFiles($"*{ImageFormat.Extension}");
47-
if (imageFiles.Length == 0)
48-
{
49-
throw new InvalidOperationException($"Dump directory [{directory.FullName}] does not contain any [*{ImageFormat.Extension}] files.");
50-
}
41+
var imageFiles = GetImageFiles(directory);
5142
var existingElements = FilterElementsForVisualization().ToDictionary(el => el.Key, el => el.Value);
5243
var countOfUnproceededElements = existingElements.Count;
5344
var countOfProceededElements = 0;
@@ -64,12 +55,21 @@ public virtual float Compare(string dumpName = null)
6455
}
6556
else
6657
{
67-
comparisonResult += existingElements[key].Visual.GetDifference(Image.FromFile(imageFile.FullName));
58+
comparisonResult += existingElements[key].Visual.GetDifference(imageFile.ReadImage());
6859
countOfUnproceededElements--;
6960
countOfProceededElements++;
7061
existingElements.Remove(key);
7162
}
7263
}
64+
LogUnproceededElements(countOfUnproceededElements, existingElements, absentOnFormElementNames);
65+
// adding of countOfUnproceededElements means 100% difference for each element absent in dump or on page
66+
var result = (comparisonResult + countOfUnproceededElements) / (countOfProceededElements + countOfUnproceededElements);
67+
LocalizedLogger.Info("loc.form.dump.compare.result", result.ToString("P", CultureInfo.InvariantCulture));
68+
return result;
69+
}
70+
71+
private void LogUnproceededElements(int countOfUnproceededElements, IDictionary<string, T> existingElements, IList<string> absentOnFormElementNames)
72+
{
7373
if (countOfUnproceededElements > 0)
7474
{
7575
if (existingElements.Any())
@@ -82,10 +82,20 @@ public virtual float Compare(string dumpName = null)
8282
}
8383
LocalizedLogger.Warn("loc.form.dump.unprocessedelements", countOfUnproceededElements);
8484
}
85-
// adding of countOfUnproceededElements means 100% difference for each element absent in dump or on page
86-
var result = (comparisonResult + countOfUnproceededElements) / (countOfProceededElements + countOfUnproceededElements);
87-
LocalizedLogger.Info("loc.form.dump.compare.result", result.ToString("P", CultureInfo.InvariantCulture));
88-
return result;
85+
}
86+
87+
private FileInfo[] GetImageFiles(DirectoryInfo directory)
88+
{
89+
if (!directory.Exists)
90+
{
91+
throw new InvalidOperationException($"Dump directory [{directory.FullName}] does not exist.");
92+
}
93+
var imageFiles = directory.GetFiles($"*{ImageFormat.Extension}");
94+
if (imageFiles.Length == 0)
95+
{
96+
throw new InvalidOperationException($"Dump directory [{directory.FullName}] does not contain any [*{ImageFormat.Extension}] files.");
97+
}
98+
return imageFiles;
8999
}
90100

91101
public virtual void Save(string dumpName = null)
@@ -170,10 +180,11 @@ protected virtual DirectoryInfo GetDumpDirectory(string dumpName = null)
170180
if (fullDumpPath.Length + maxNameLengthOfDumpElements > MaxFullFileNameLength)
171181
{
172182
validDumpNameString = validDumpNameString.Substring(0, MaxFullFileNameLength - Path.GetFullPath(DumpsDirectory).Length - maxNameLengthOfDumpElements);
173-
LocalizedLogger.Warn("loc.form.dump.exceededdumpname", validDumpNameString);
183+
fullDumpPath = Path.Combine(DumpsDirectory, validDumpNameString);
184+
LocalizedLogger.Warn("loc.form.dump.exceededdumpname", fullDumpPath);
174185
}
175186

176-
return new DirectoryInfo(Path.Combine(DumpsDirectory, validDumpNameString));
187+
return new DirectoryInfo(fullDumpPath);
177188
}
178189
}
179190
}

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Visualization/IImageComparator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using Aquality.Selenium.Core.Configurations;
2-
using System.Drawing;
2+
using SkiaSharp;
33

44
namespace Aquality.Selenium.Core.Visualization
55
{
@@ -17,6 +17,6 @@ public interface IImageComparator
1717
/// <param name="theOtherOne">The image to compare with</param>
1818
/// <param name="threshold">How big a difference will be ignored as a percentage - value between 0 and 1. </param>
1919
/// <returns>The difference between the two images as a percentage - value between 0 and 1.</returns>
20-
float PercentageDifference(Image thisOne, Image theOtherOne, float? threshold = null);
20+
float PercentageDifference(SKImage thisOne, SKImage theOtherOne, float? threshold = null);
2121
}
2222
}

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Visualization/IVisualStateProvider.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Aquality.Selenium.Core.Configurations;
2+
using SkiaSharp;
23
using System.Drawing;
34

45
namespace Aquality.Selenium.Core.Visualization
@@ -22,7 +23,7 @@ public interface IVisualStateProvider
2223
/// <summary>
2324
/// Gets an image containing the screenshot of the element.
2425
/// </summary>
25-
Image Image { get; }
26+
SKImage Image { get; }
2627

2728
/// <summary>
2829
/// Gets the difference between the image of the element and the provided image
@@ -32,6 +33,6 @@ public interface IVisualStateProvider
3233
/// <param name="threshold">How big a difference will be ignored as a percentage - value between 0 and 1.
3334
/// If the value is null, the default value is got from <see cref="IVisualizationConfiguration"/>.</param>
3435
/// <returns>The difference between the two images as a percentage - value between 0 and 1.</returns>
35-
float GetDifference(Image theOtherOne, float? threshold = null);
36+
float GetDifference(SKImage theOtherOne, float? threshold = null);
3637
}
3738
}

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Visualization/ImageComparator.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Aquality.Selenium.Core.Configurations;
2+
using SkiaSharp;
23
using System;
3-
using System.Drawing;
44

55
namespace Aquality.Selenium.Core.Visualization
66
{
@@ -33,7 +33,7 @@ public ImageComparator(IVisualizationConfiguration visualizationConfiguration)
3333
/// If the value is null, the default value is got from <see cref="IVisualizationConfiguration"/>.</param>
3434
/// <returns>The difference between the two images as a percentage - value between 0 and 1.</returns>
3535
/// <remarks>See https://web.archive.org/web/20130208001434/http://tech.pro:80/tutorial/660/csharp-tutorial-convert-a-color-image-to-grayscale for more details.</remarks>
36-
public virtual float PercentageDifference(Image thisOne, Image theOtherOne, float? threshold = null)
36+
public virtual float PercentageDifference(SKImage thisOne, SKImage theOtherOne, float? threshold = null)
3737
{
3838
var thresholdValue = threshold ?? DefaultThreshold;
3939
if (thresholdValue < 0 || thresholdValue > 1)
@@ -53,7 +53,7 @@ public virtual float PercentageDifference(Image thisOne, Image theOtherOne, floa
5353
/// <param name="threshold">How big a difference (out of 255) will be ignored - the default is 3.</param>
5454
/// <returns>The difference between the two images as a percentage</returns>
5555
/// <remarks>See https://web.archive.org/web/20130208001434/http://tech.pro:80/tutorial/660/csharp-tutorial-convert-a-color-image-to-grayscale for more details</remarks>
56-
protected virtual float PercentageDifference(Image thisOne, Image theOtherOne, byte threshold = 3)
56+
protected virtual float PercentageDifference(SKImage thisOne, SKImage theOtherOne, byte threshold = 3)
5757
{
5858
var differences = GetDifferences(thisOne, theOtherOne);
5959

@@ -73,7 +73,7 @@ protected virtual float PercentageDifference(Image thisOne, Image theOtherOne, b
7373
/// <param name="thisOne">The first image</param>
7474
/// <param name="theOtherOne">The image to compare with</param>
7575
/// <returns>the differences between the two images as a double-array</returns>
76-
protected virtual byte[,] GetDifferences(Image thisOne, Image theOtherOne)
76+
protected virtual byte[,] GetDifferences(SKImage thisOne, SKImage theOtherOne)
7777
{
7878
var firstGray = GetResizedGrayScaleValues(thisOne);
7979
var secondGray = GetResizedGrayScaleValues(theOtherOne);
@@ -95,17 +95,17 @@ protected virtual float PercentageDifference(Image thisOne, Image theOtherOne, b
9595
/// </summary>
9696
/// <param name="img">The image to get the lightness for</param>
9797
/// <returns>A double-array (16x16 by default) containing the lightness of the sections(256 by default)</returns>
98-
protected virtual byte[,] GetResizedGrayScaleValues(Image img)
98+
protected virtual byte[,] GetResizedGrayScaleValues(SKImage img)
9999
{
100-
using (var thisOne = (Bitmap)img.Resize(ComparisonWidth, ComparisonHeight).GetGrayScaleVersion())
100+
using (var thisOne = SKBitmap.FromImage(img.Resize(ComparisonWidth, ComparisonHeight).GetGrayScaleVersion()))
101101
{
102102
byte[,] grayScale = new byte[thisOne.Width, thisOne.Height];
103103

104104
for (int y = 0; y < thisOne.Height; y++)
105105
{
106106
for (int x = 0; x < thisOne.Width; x++)
107107
{
108-
grayScale[x, y] = (byte)Math.Abs(thisOne.GetPixel(x, y).R);
108+
grayScale[x, y] = (byte)Math.Abs(thisOne.GetPixel(x, y).Red);
109109
}
110110
}
111111

0 commit comments

Comments
 (0)