From 66709893be79013dc6972bea6e3570338576a98c Mon Sep 17 00:00:00 2001
From: Christopher Regali
Date: Tue, 27 Feb 2024 23:50:11 +0100
Subject: [PATCH 01/14] First shot at adding more image compare options
---
Cargo.toml | 2 +-
src/image.rs | 188 ++++++++++++++++++++++++++++++++++++-----
src/lib.rs | 7 +-
src/report/mod.rs | 17 ++--
src/report/template.rs | 2 +
5 files changed, 184 insertions(+), 32 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 746e55c..ee30050 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ description = "A flexible rule-based file and folder comparison tool and crate i
repository = "https://github.com/VolumeGraphics/havocompare"
homepage = "https://github.com/VolumeGraphics/havocompare"
documentation = "https://docs.rs/havocompare"
-version = "0.5.4"
+version = "0.6.0"
edition = "2021"
license = "MIT"
authors = ["Volume Graphics GmbH"]
diff --git a/src/image.rs b/src/image.rs
index 8fa5671..a695dc6 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -1,5 +1,7 @@
use crate::report::DiffDetail;
use crate::{get_file_name, report};
+use image::{DynamicImage, Rgb};
+use image_compare::{Algorithm, Metric, Similarity};
use schemars_derive::JsonSchema;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
@@ -7,23 +9,68 @@ use thiserror::Error;
use tracing::error;
#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
-/// Image comparison config options
-pub struct ImageCompareConfig {
- /// Threshold for image comparison < 0.5 is very dissimilar, 1.0 is identical
- pub threshold: f64,
+pub enum RGBACompareMode {
+ /// full RGBA comparison - probably not intuitive, rarely what you want outside of video processing
+ /// Will do MSSIM on luma, then RMS on U and V and alpha channels.
+ /// The calculation of the score is then pixel-wise the minimum of each pixels similarity.
+ /// To account for perceived indifference in lower alpha regions, this down-weights the difference linearly with mean alpha channel.
+ Hybrid,
+ /// pre-blend the background in RGBA with this color, use the background RGB values you would assume the pictures to be seen on - usually either black or white
+ HybridBlended { r: u8, b: u8, g: u8 },
}
-impl ImageCompareConfig {
- /// create an [`ImageCompareConfig`] given the threshold
- pub fn from_threshold(threshold: f64) -> Self {
- ImageCompareConfig { threshold }
+impl Default for RGBACompareMode {
+ fn default() -> Self {
+ Self::HybridBlended { r: 0, b: 0, g: 0 }
}
}
-impl Default for ImageCompareConfig {
- fn default() -> Self {
- ImageCompareConfig::from_threshold(1.0)
- }
+#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone, Default)]
+pub enum RGBCompareMode {
+ ///Comparing rgb images using structure. RGB structure similarity is performed by doing a channel split and taking the maximum deviation (minimum similarity) for the result. The image contains the complete deviations. Algorithm: RMS
+ RMS,
+ ///Comparing rgb images using structure. RGB structure similarity is performed by doing a channel split and taking the maximum deviation (minimum similarity) for the result. The image contains the complete deviations. Algorithm: MSSIM
+ MSSIM,
+ ///Comparing structure via MSSIM on Y channel, comparing color-diff-vectors on U and V summing the squares Please mind that the RGBSimilarity-Image does not contain plain RGB here. Probably what you want.
+ #[default]
+ Hybrid,
+}
+
+#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
+pub enum GrayStructureAlgorithm {
+ MSSIM,
+ RMS,
+}
+
+#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
+pub enum GrayHistogramCompareMetric {
+ Correlation,
+ ChiSquare,
+ Intersection,
+ Hellinger,
+}
+
+#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
+pub enum GrayCompareMode {
+ Structure(GrayStructureAlgorithm),
+ Histogram(GrayHistogramCompareMetric),
+}
+
+#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
+pub enum CompareMode {
+ RGB(RGBCompareMode),
+ RGBA(RGBACompareMode),
+ Gray(GrayCompareMode),
+}
+
+#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
+/// Image comparison config options
+pub struct ImageCompareConfig {
+ /// Threshold for image comparison < 0.5 is very dissimilar, 1.0 is identical
+ pub threshold: f64,
+ #[serde(flatten)]
+ /// How to compare the two images
+ pub mode: CompareMode,
}
#[derive(Debug, Error)]
@@ -38,15 +85,99 @@ pub enum Error {
FileNameParsing(String),
}
+struct ComparisonResult {
+ score: f64,
+ image: Option,
+}
+
+impl From for ComparisonResult {
+ fn from(value: Similarity) -> Self {
+ Self {
+ image: Some(value.image.to_color_map()),
+ score: value.score,
+ }
+ }
+}
+
pub fn compare_paths>(
nominal_path: P,
actual_path: P,
config: &ImageCompareConfig,
) -> Result {
- let nominal = image::open(nominal_path.as_ref())?.into_rgba8();
- let actual = image::open(actual_path.as_ref())?.into_rgba8();
+ let nominal = image::open(nominal_path.as_ref())?;
+ let actual = image::open(actual_path.as_ref())?;
+ let result: ComparisonResult = match &config.mode {
+ CompareMode::RGBA(c) => {
+ let nominal = nominal.into_rgba8();
+ let actual = actual.into_rgba8();
+ match c {
+ RGBACompareMode::Hybrid => {
+ image_compare::rgba_hybrid_compare(&nominal, &actual)?.into()
+ }
+ RGBACompareMode::HybridBlended { r, g, b } => {
+ image_compare::rgba_blended_hybrid_compare(
+ (&nominal).into(),
+ (&actual).into(),
+ Rgb([*r, *g, *b]),
+ )?
+ .into()
+ }
+ }
+ }
+ CompareMode::RGB(c) => {
+ let nominal = nominal.into_rgb8();
+ let actual = actual.into_rgb8();
+ match c {
+ RGBCompareMode::RMS => image_compare::rgb_similarity_structure(
+ &Algorithm::RootMeanSquared,
+ &nominal,
+ &actual,
+ )?
+ .into(),
+ RGBCompareMode::MSSIM => image_compare::rgb_similarity_structure(
+ &Algorithm::MSSIMSimple,
+ &nominal,
+ &actual,
+ )?
+ .into(),
+ RGBCompareMode::Hybrid => {
+ image_compare::rgb_hybrid_compare(&nominal, &actual)?.into()
+ }
+ }
+ }
+ CompareMode::Gray(c) => {
+ let nominal = nominal.into_luma8();
+ let actual = actual.into_luma8();
+ match c {
+ GrayCompareMode::Structure(c) => match c {
+ GrayStructureAlgorithm::MSSIM => image_compare::gray_similarity_structure(
+ &Algorithm::MSSIMSimple,
+ &nominal,
+ &actual,
+ )?
+ .into(),
+ GrayStructureAlgorithm::RMS => image_compare::gray_similarity_structure(
+ &Algorithm::RootMeanSquared,
+ &nominal,
+ &actual,
+ )?
+ .into(),
+ },
+ GrayCompareMode::Histogram(c) => {
+ let metric = match c {
+ GrayHistogramCompareMetric::Correlation => Metric::Correlation,
+ GrayHistogramCompareMetric::ChiSquare => Metric::ChiSquare,
+ GrayHistogramCompareMetric::Intersection => Metric::Intersection,
+ GrayHistogramCompareMetric::Hellinger => Metric::Hellinger,
+ };
+ let score =
+ image_compare::gray_similarity_histogram(metric, &nominal, &actual)?;
+ ComparisonResult { score, image: None }
+ }
+ }
+ }
+ };
- let result = image_compare::rgba_hybrid_compare(&nominal, &actual)?;
let nominal_file_name =
get_file_name(nominal_path.as_ref()).ok_or(Error::FileNameParsing(format!(
"Could not extract filename from path {:?}",
@@ -56,8 +187,13 @@ pub fn compare_paths>(
let mut result_diff = report::Difference::new_for_file(&nominal_path, &actual_path);
if result.score < config.threshold {
- let color_map = result.image.to_color_map();
- color_map.save(PathBuf::from(&out_path))?;
+ let out_path_set;
+ if let Some(i) = result.image {
+ i.save(PathBuf::from(&out_path))?;
+ out_path_set = Some(out_path);
+ } else {
+ out_path_set = None;
+ }
let error_message = format!(
"Diff for image {} was not met, expected {}, found {}",
@@ -66,8 +202,9 @@ pub fn compare_paths>(
result.score
);
error!("{}", &error_message);
+
result_diff.push_detail(DiffDetail::Image {
- diff_image: out_path,
+ diff_image: out_path_set,
score: result.score,
});
result_diff.error();
@@ -77,6 +214,7 @@ pub fn compare_paths>(
#[cfg(test)]
mod test {
+ use super::*;
use crate::image::{compare_paths, ImageCompareConfig};
use crate::report::DiffDetail;
@@ -85,7 +223,10 @@ mod test {
let result = compare_paths(
"tests/integ/data/images/actual/SaveImage_100DPI_default_size.jpg",
"tests/integ/data/images/actual/SaveImage_100DPI_default_size.jpg",
- &ImageCompareConfig { threshold: 1.0 },
+ &ImageCompareConfig {
+ threshold: 1.0,
+ mode: CompareMode::RGB(RGBCompareMode::Hybrid),
+ },
)
.unwrap();
assert!(!result.is_error);
@@ -96,7 +237,10 @@ mod test {
let result = compare_paths(
"tests/integ/data/images/expected/SaveImage_100DPI_default_size.jpg",
"tests/integ/data/images/actual/SaveImage_100DPI_default_size.jpg",
- &ImageCompareConfig { threshold: 1.0 },
+ &ImageCompareConfig {
+ threshold: 1.0,
+ mode: CompareMode::RGB(RGBCompareMode::Hybrid),
+ },
)
.unwrap();
assert!(result.is_error);
@@ -105,7 +249,9 @@ mod test {
diff_image,
} = result.detail.first().unwrap()
{
- let img = image::open(diff_image).unwrap().into_rgb8();
+ let img = image::open(diff_image.as_ref().unwrap())
+ .unwrap()
+ .into_rgb8();
let nom = image::open("tests/integ/data/images/diff_100_DPI.png")
.unwrap()
.into_rgb8();
diff --git a/src/lib.rs b/src/lib.rs
index 15c5063..ff4aeb6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -379,12 +379,15 @@ pub fn validate_config(config_file: impl AsRef) -> bool {
#[cfg(test)]
mod tests {
use super::*;
- use crate::image::ImageCompareConfig;
+ use crate::image::{CompareMode, ImageCompareConfig, RGBCompareMode};
#[test]
fn folder_not_found_is_false() {
let rule = Rule {
name: "test rule".to_string(),
- file_type: ComparisonMode::Image(ImageCompareConfig { threshold: 1.0 }),
+ file_type: ComparisonMode::Image(ImageCompareConfig {
+ threshold: 1.0,
+ mode: CompareMode::RGB(RGBCompareMode::Hybrid),
+ }),
pattern_include: vec!["*.".to_string()],
pattern_exclude: None,
};
diff --git a/src/report/mod.rs b/src/report/mod.rs
index ab2e7e2..b8a4f49 100644
--- a/src/report/mod.rs
+++ b/src/report/mod.rs
@@ -130,7 +130,7 @@ pub enum DiffDetail {
CSV(DiffType),
Image {
score: f64,
- diff_image: String,
+ diff_image: Option,
},
Text {
actual: String,
@@ -352,7 +352,7 @@ pub(crate) fn write_csv_detail(
pub fn write_image_detail(
nominal: impl AsRef,
actual: impl AsRef,
- diffs: &[(&f64, &String)],
+ diffs: &[(&f64, &Option)],
report_dir: impl AsRef,
) -> Result
+{% if diff_image %}
Diff:
+{% endif %}
From 376989365a4cc24aac48e7ca2d733aca0391623c Mon Sep 17 00:00:00 2001
From: Christopher Regali
Date: Wed, 28 Feb 2024 00:03:00 +0100
Subject: [PATCH 02/14] Fix tests and update schema
---
config_scheme.json | 153 ++++++++++++++++++++++++++++++++++++
tests/integ/jpg_compare.yml | 1 +
2 files changed, 154 insertions(+)
diff --git a/config_scheme.json b/config_scheme.json
index 3670404..18238b0 100644
--- a/config_scheme.json
+++ b/config_scheme.json
@@ -87,6 +87,50 @@
}
}
},
+ "GrayCompareMode": {
+ "oneOf": [
+ {
+ "type": "object",
+ "required": [
+ "Structure"
+ ],
+ "properties": {
+ "Structure": {
+ "$ref": "#/definitions/GrayStructureAlgorithm"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "required": [
+ "Histogram"
+ ],
+ "properties": {
+ "Histogram": {
+ "$ref": "#/definitions/GrayHistogramCompareMetric"
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "GrayHistogramCompareMetric": {
+ "type": "string",
+ "enum": [
+ "Correlation",
+ "ChiSquare",
+ "Intersection",
+ "Hellinger"
+ ]
+ },
+ "GrayStructureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "MSSIM",
+ "RMS"
+ ]
+ },
"HTMLCompareConfig": {
"description": "Plain text comparison config, also used for PDF",
"type": "object",
@@ -137,6 +181,44 @@
"ImageCompareConfig": {
"description": "Image comparison config options",
"type": "object",
+ "oneOf": [
+ {
+ "type": "object",
+ "required": [
+ "RGB"
+ ],
+ "properties": {
+ "RGB": {
+ "$ref": "#/definitions/RGBCompareMode"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "required": [
+ "RGBA"
+ ],
+ "properties": {
+ "RGBA": {
+ "$ref": "#/definitions/RGBACompareMode"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "required": [
+ "Gray"
+ ],
+ "properties": {
+ "Gray": {
+ "$ref": "#/definitions/GrayCompareMode"
+ }
+ },
+ "additionalProperties": false
+ }
+ ],
"required": [
"threshold"
],
@@ -392,6 +474,77 @@
}
}
},
+ "RGBACompareMode": {
+ "oneOf": [
+ {
+ "description": "full RGBA comparison - probably not intuitive, rarely what you want outside of video processing Will do MSSIM on luma, then RMS on U and V and alpha channels. The calculation of the score is then pixel-wise the minimum of each pixels similarity. To account for perceived indifference in lower alpha regions, this down-weights the difference linearly with mean alpha channel.",
+ "type": "string",
+ "enum": [
+ "Hybrid"
+ ]
+ },
+ {
+ "description": "pre-blend the background in RGBA with this color, use the background RGB values you would assume the pictures to be seen on - usually either black or white",
+ "type": "object",
+ "required": [
+ "HybridBlended"
+ ],
+ "properties": {
+ "HybridBlended": {
+ "type": "object",
+ "required": [
+ "b",
+ "g",
+ "r"
+ ],
+ "properties": {
+ "b": {
+ "type": "integer",
+ "format": "uint8",
+ "minimum": 0.0
+ },
+ "g": {
+ "type": "integer",
+ "format": "uint8",
+ "minimum": 0.0
+ },
+ "r": {
+ "type": "integer",
+ "format": "uint8",
+ "minimum": 0.0
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "RGBCompareMode": {
+ "oneOf": [
+ {
+ "description": "Comparing rgb images using structure. RGB structure similarity is performed by doing a channel split and taking the maximum deviation (minimum similarity) for the result. The image contains the complete deviations. Algorithm: RMS",
+ "type": "string",
+ "enum": [
+ "RMS"
+ ]
+ },
+ {
+ "description": "Comparing rgb images using structure. RGB structure similarity is performed by doing a channel split and taking the maximum deviation (minimum similarity) for the result. The image contains the complete deviations. Algorithm: MSSIM",
+ "type": "string",
+ "enum": [
+ "MSSIM"
+ ]
+ },
+ {
+ "description": "Comparing structure via MSSIM on Y channel, comparing color-diff-vectors on U and V summing the squares Please mind that the RGBSimilarity-Image does not contain plain RGB here. Probably what you want.",
+ "type": "string",
+ "enum": [
+ "Hybrid"
+ ]
+ }
+ ]
+ },
"Rule": {
"description": "Representing a single comparison rule",
"type": "object",
diff --git a/tests/integ/jpg_compare.yml b/tests/integ/jpg_compare.yml
index ffba804..57d0047 100644
--- a/tests/integ/jpg_compare.yml
+++ b/tests/integ/jpg_compare.yml
@@ -3,4 +3,5 @@ rules:
pattern_include:
- "**/*.jpg"
Image:
+ RGBA: Hybrid
threshold: 0.9
From d685e55d34e400cadc1d4abd3c7b944f1c7d0a27 Mon Sep 17 00:00:00 2001
From: Christopher Regali <60792386+ChrisRega@users.noreply.github.com>
Date: Fri, 1 Mar 2024 22:17:49 +0100
Subject: [PATCH 03/14] Update src/image.rs
Co-authored-by: Alexander Rohde
---
src/image.rs | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/image.rs b/src/image.rs
index a695dc6..13758be 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -185,6 +185,19 @@ pub fn compare_paths>(
)))?;
let out_path = (nominal_file_name + "diff_image.png").to_string();
let mut result_diff = report::Difference::new_for_file(&nominal_path, &actual_path);
+ if result.score < config.threshold {
+ let out_path_set = if let Some(i) = result.image {
+ let nominal_file_name =
+ get_file_name(nominal_path.as_ref()).ok_or(Error::FileNameParsing(format!(
+ "Could not extract filename from path {:?}",
+ nominal_path.as_ref()
+ )))?;
+ let out_path = (nominal_file_name + "diff_image.png").to_string();
+ i.save(&out_path)?;
+ Some(out_path)
+ } else {
+ None
+ };
if result.score < config.threshold {
let out_path_set;
From ba894a7e4487f498011033808d792b32a0165218 Mon Sep 17 00:00:00 2001
From: Christopher Regali
Date: Fri, 1 Mar 2024 22:39:45 +0100
Subject: [PATCH 04/14] Fix merge suggestion
---
src/image.rs | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/src/image.rs b/src/image.rs
index 13758be..c74c394 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -4,7 +4,7 @@ use image::{DynamicImage, Rgb};
use image_compare::{Algorithm, Metric, Similarity};
use schemars_derive::JsonSchema;
use serde::{Deserialize, Serialize};
-use std::path::{Path, PathBuf};
+use std::path::Path;
use thiserror::Error;
use tracing::error;
@@ -178,12 +178,6 @@ pub fn compare_paths>(
}
};
- let nominal_file_name =
- get_file_name(nominal_path.as_ref()).ok_or(Error::FileNameParsing(format!(
- "Could not extract filename from path {:?}",
- nominal_path.as_ref()
- )))?;
- let out_path = (nominal_file_name + "diff_image.png").to_string();
let mut result_diff = report::Difference::new_for_file(&nominal_path, &actual_path);
if result.score < config.threshold {
let out_path_set = if let Some(i) = result.image {
@@ -199,15 +193,6 @@ pub fn compare_paths>(
None
};
- if result.score < config.threshold {
- let out_path_set;
- if let Some(i) = result.image {
- i.save(PathBuf::from(&out_path))?;
- out_path_set = Some(out_path);
- } else {
- out_path_set = None;
- }
-
let error_message = format!(
"Diff for image {} was not met, expected {}, found {}",
nominal_path.as_ref().to_string_lossy(),
From ad27fff241a0bfd5681581f2df5503420f9274b7 Mon Sep 17 00:00:00 2001
From: Christopher Regali
Date: Sun, 17 Mar 2024 22:46:30 +0100
Subject: [PATCH 05/14] add some more commentary
---
src/image.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/image.rs b/src/image.rs
index c74c394..5de8847 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -37,11 +37,17 @@ pub enum RGBCompareMode {
}
#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
+/// The distance algorithm to use for grayscale comparison, see
+/// https://github.com/ChrisRega/image-compare for equations
pub enum GrayStructureAlgorithm {
+ /// SSIM with 8x8 pixel windows and averaging over the result
MSSIM,
+ /// Classic RMS distance
RMS,
}
+/// See https://github.com/ChrisRega/image-compare for equations
+/// Distance metrics for histograms for grayscale comparison
#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone)]
pub enum GrayHistogramCompareMetric {
Correlation,
From f8545867d45bc16e471bb325f7bdefbadca471e2 Mon Sep 17 00:00:00 2001
From: Christopher Regali
Date: Sat, 23 Mar 2024 23:13:29 +0100
Subject: [PATCH 06/14] Bump image to 0.25, image-compare to 0.4.0
---
Cargo.toml | 20 ++++++++++----------
src/image.rs | 10 ++++------
src/lib.rs | 2 +-
tests/integ/data/images/diff_100_DPI.png | Bin 152512 -> 131424 bytes
4 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index ee30050..c3f7440 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2021"
license = "MIT"
authors = ["Volume Graphics GmbH"]
exclude = ["tests/pdf", "tests/integ", "tests/html", "target", "tests/csv", ".github", "test_report"]
-keywords = ["diff" ,"compare", "csv", "image", "difference"]
+keywords = ["diff", "compare", "csv", "image", "difference"]
categories = ["filesystem"]
default-run = "havocompare"
@@ -19,7 +19,7 @@ path = "src/print_args.rs"
[dependencies]
-clap = {version= "4.4", features=["derive"]}
+clap = { version = "4.4", features = ["derive"] }
chrono = "0.4"
serde = "1.0"
serde_yaml = "0.9"
@@ -27,13 +27,13 @@ schemars = "0.8"
schemars_derive = "0.8"
thiserror = "1.0"
regex = "1.10"
-image = "0.24"
-image-compare = "0.3"
+image = "0.25"
+image-compare = "0.4"
tracing = "0.1"
tracing-subscriber = "0.3"
serde_json = "1.0"
glob = "0.3"
-test-log = {version="0.2", features=["trace"]}
+test-log = { version = "0.2", features = ["trace"] }
strsim = "0.11"
itertools = "0.12"
tera = "1.19"
@@ -42,16 +42,16 @@ data-encoding = "2.5"
permutation = "0.4"
pdf-extract = "0.7"
vg_errortools = "0.1"
-rayon = "1.8.0"
+rayon = "1.9.0"
enable-ansi-support = "0.2"
tempfile = "3.8"
fs_extra = "1.3"
-opener = "0.6"
+opener = "0.7"
anyhow = "1.0"
-json_diff_ng = {version = "0.4"}
+json_diff_ng = { version = "0.4" }
[dev-dependencies]
env_logger = "0.11"
-tracing = {version = "0.1", default-features = false}
-tracing-subscriber = {version = "0.3", default-features = false, features = ["env-filter", "fmt"]}
+tracing = { version = "0.1", default-features = false }
+tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"] }
diff --git a/src/image.rs b/src/image.rs
index 5de8847..f22bbb7 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -219,8 +219,6 @@ pub fn compare_paths>(
#[cfg(test)]
mod test {
use super::*;
- use crate::image::{compare_paths, ImageCompareConfig};
- use crate::report::DiffDetail;
#[test]
fn identity() {
@@ -243,7 +241,7 @@ mod test {
"tests/integ/data/images/actual/SaveImage_100DPI_default_size.jpg",
&ImageCompareConfig {
threshold: 1.0,
- mode: CompareMode::RGB(RGBCompareMode::Hybrid),
+ mode: CompareMode::RGBA(RGBACompareMode::Hybrid),
},
)
.unwrap();
@@ -255,11 +253,11 @@ mod test {
{
let img = image::open(diff_image.as_ref().unwrap())
.unwrap()
- .into_rgb8();
+ .into_rgba8();
let nom = image::open("tests/integ/data/images/diff_100_DPI.png")
.unwrap()
- .into_rgb8();
- let diff_result = image_compare::rgb_hybrid_compare(&img, &nom)
+ .into_rgba8();
+ let diff_result = image_compare::rgba_hybrid_compare(&img, &nom)
.expect("Wrong dimensions of diff images!");
assert_eq!(diff_result.score, 1.0);
} else {
diff --git a/src/lib.rs b/src/lib.rs
index ff4aeb6..58fccdc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -379,7 +379,7 @@ pub fn validate_config(config_file: impl AsRef) -> bool {
#[cfg(test)]
mod tests {
use super::*;
- use crate::image::{CompareMode, ImageCompareConfig, RGBCompareMode};
+ use crate::image::{CompareMode, RGBCompareMode};
#[test]
fn folder_not_found_is_false() {
let rule = Rule {
diff --git a/tests/integ/data/images/diff_100_DPI.png b/tests/integ/data/images/diff_100_DPI.png
index 4d0ae5caab76d276bf558470cc2fa6126c4c5562..316f83d33af25dc2dbac8b7161737897a64be07e 100644
GIT binary patch
literal 131424
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