Skip to main content

semdiff_differ_image/
report_json.rs

1use crate::{ImageDiff, ImageDiffReporter, image_format};
2use image::ImageError;
3use semdiff_core::fs::FileLeaf;
4use semdiff_core::{DetailReporter, MayUnsupported};
5use semdiff_output::json::JsonReport;
6use serde::Serialize;
7use thiserror::Error;
8
9const COMPARES_NAME: &str = "image";
10
11#[derive(Debug, Error)]
12pub enum ImageJsonReportError {
13    #[error("image decode error: {0}")]
14    ImageDecode(#[from] ImageError),
15}
16
17impl<W> DetailReporter<ImageDiff, FileLeaf, JsonReport<W>> for ImageDiffReporter {
18    type Error = ImageJsonReportError;
19
20    fn report_unchanged(
21        &self,
22        name: &str,
23        _diff: ImageDiff,
24        reporter: &JsonReport<W>,
25    ) -> Result<MayUnsupported<()>, Self::Error> {
26        reporter.record_unchanged(name, COMPARES_NAME, ());
27        Ok(MayUnsupported::Ok(()))
28    }
29
30    fn report_modified(
31        &self,
32        name: &str,
33        diff: ImageDiff,
34        reporter: &JsonReport<W>,
35    ) -> Result<MayUnsupported<()>, Self::Error> {
36        let report = ModifiedReport {
37            expected_width: diff.expected().width,
38            expected_height: diff.expected().height,
39            actual_width: diff.actual().width,
40            actual_height: diff.actual().height,
41            diff_pixels: diff.diff_stat().diff_pixels,
42        };
43        reporter.record_modified(name, COMPARES_NAME, report);
44        Ok(MayUnsupported::Ok(()))
45    }
46
47    fn report_added(
48        &self,
49        name: &str,
50        data: FileLeaf,
51        reporter: &JsonReport<W>,
52    ) -> Result<MayUnsupported<()>, Self::Error> {
53        let Some(format) = image_format(&data.kind) else {
54            return Ok(MayUnsupported::Unsupported);
55        };
56        let image = image::load_from_memory_with_format(&data.content, format)?;
57        let report = SingleReport {
58            width: image.width(),
59            height: image.height(),
60        };
61        reporter.record_added(name, COMPARES_NAME, report);
62        Ok(MayUnsupported::Ok(()))
63    }
64
65    fn report_deleted(
66        &self,
67        name: &str,
68        data: FileLeaf,
69        reporter: &JsonReport<W>,
70    ) -> Result<MayUnsupported<()>, Self::Error> {
71        let Some(format) = image_format(&data.kind) else {
72            return Ok(MayUnsupported::Unsupported);
73        };
74        let image = image::load_from_memory_with_format(&data.content, format)?;
75        let report = SingleReport {
76            width: image.width(),
77            height: image.height(),
78        };
79        reporter.record_deleted(name, COMPARES_NAME, report);
80        Ok(MayUnsupported::Ok(()))
81    }
82}
83
84#[derive(Serialize)]
85struct ModifiedReport {
86    expected_width: u32,
87    expected_height: u32,
88    actual_width: u32,
89    actual_height: u32,
90    diff_pixels: u64,
91}
92
93#[derive(Serialize)]
94struct SingleReport {
95    width: u32,
96    height: u32,
97}