1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//! SSIMULACRA2, a perceptual full-reference metric.
//!
//! This binds the original C++ reference implementation
//! ([cloudinary/ssimulacra2]) via FFI rather than reimplementing it in Rust,
//! keeping results faithful to upstream. The C++ sources are vendored as git
//! submodules under `third_party/` and compiled by `build.rs`.
//!
//! [cloudinary/ssimulacra2]: https://github.com/cloudinary/ssimulacra2
use crate;
use crate;
use crateImage;
/// Minimum width and height the reference implementation accepts.
const MIN_DIMENSION: u32 = 8;
/// A pixel format that [`ssimulacra2`] can score.
///
/// SSIMULACRA2's reference implementation requires sRGB-encoded input, so this
/// trait is implemented only for the sRGB-family formats (grayscale counts: it
/// is treated as sRGB-encoded luma). It is the seam that keeps a non-sRGB
/// image from reaching the metric: were a linear-light format added to the
/// crate, omitting its `Ssimulacra2Input` impl would make passing it to
/// [`ssimulacra2`] a compile error, with no change to the function signature.
/// Computes the SSIMULACRA2 score between `reference` and `distorted`.
///
/// The score ranges up to `100` (mathematically lossless) and is unbounded
/// below; higher is better. Both images share the format `F`, which the
/// [`Ssimulacra2Input`] bound additionally constrains to an sRGB-family
/// format. Each must be at least 8x8.
///
/// # Errors
///
/// - [`Error::DimensionMismatch`] if the images differ in size.
/// - [`Error::ImageTooSmall`] if either dimension is below 8 pixels.
/// - [`Error::Ssimulacra2Failed`] if the native implementation reports failure.
///
/// # Examples
///
/// ```no_run
/// use iqa::{Image, ssimulacra2};
///
/// let reference = Image::srgb8(8, 8, vec![128; 192])?;
/// let distorted = Image::srgb8(8, 8, vec![130; 192])?;
/// let score = ssimulacra2(&reference, &distorted)?;
/// assert!(score <= 100.0);
/// # Ok::<(), iqa::Error>(())
/// ```
///
/// Comparing two different pixel formats does not type-check:
///
/// ```compile_fail
/// use iqa::{Image, ssimulacra2};
///
/// let rgb = Image::srgb8(8, 8, vec![0; 192])?;
/// let gray = Image::gray8(8, 8, vec![0; 64])?;
/// let _ = ssimulacra2(&rgb, &gray); // mismatched formats
/// # Ok::<(), iqa::Error>(())
/// ```