semdiff_differ_image/
report_json.rs1use 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}