98 lines
3.1 KiB
Rust
98 lines
3.1 KiB
Rust
use native_core::thumbhash::decode;
|
|
|
|
// Expected pixels come from the old Swift decoder patched to round like the Java did (it truncated),
|
|
// taken at pixels whose values sit well away from a rounding boundary, so the check is exact on any libm.
|
|
const LANDSCAPE: &[u8] = &[
|
|
0xdc, 0xf7, 0x0d, 0x35, 0x84, 0x85, 0x79, 0x78, 0x7f, 0x77, 0x77, 0xa5, 0x77, 0x48, 0x87, 0x66,
|
|
0x86, 0x60, 0x57, 0x08, 0x76,
|
|
];
|
|
const PORTRAIT: &[u8] = &[
|
|
0x93, 0x4a, 0x06, 0x2d, 0x06, 0x92, 0x56, 0xc3, 0x74, 0x05, 0x58, 0x67, 0xda, 0x8a, 0xb6, 0x67,
|
|
0x94, 0x90, 0x51, 0x07, 0x19,
|
|
];
|
|
const ALPHA: &[u8] = &[
|
|
0x60, 0x9a, 0x86, 0x3d, 0x0c, 0x3b, 0xb0, 0x59, 0x6c, 0x96, 0xa8, 0x45, 0x69, 0xf4, 0x84, 0xf9,
|
|
0x0e, 0xa8, 0x27, 0x58, 0x76, 0x88, 0x70, 0x76, 0x47,
|
|
];
|
|
|
|
fn check(name: &str, hash: &[u8], size: (u32, u32), samples: &[(u32, u32, [u8; 4])]) {
|
|
let mut rgba = [0; 32 * 32 * 4];
|
|
let (width, height) = decode(hash, &mut rgba).unwrap();
|
|
assert_eq!((width, height), size, "{name}");
|
|
for &(x, y, expected) in samples {
|
|
let i = ((y * width + x) * 4) as usize;
|
|
assert_eq!(rgba[i..i + 4], expected, "{name} pixel {x},{y}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn matches_swift_placeholders() {
|
|
check(
|
|
"landscape",
|
|
LANDSCAPE,
|
|
(32, 23),
|
|
&[
|
|
(0, 0, [48, 83, 154, 255]),
|
|
(11, 0, [59, 90, 156, 255]),
|
|
(20, 0, [91, 113, 163, 255]),
|
|
(29, 1, [109, 123, 156, 255]),
|
|
(1, 11, [84, 92, 96, 255]),
|
|
(10, 11, [77, 84, 89, 255]),
|
|
(20, 11, [143, 144, 141, 255]),
|
|
(30, 10, [164, 161, 153, 255]),
|
|
(1, 22, [98, 84, 35, 255]),
|
|
(9, 21, [69, 56, 12, 255]),
|
|
(19, 22, [87, 72, 30, 255]),
|
|
(30, 22, [79, 60, 13, 255]),
|
|
],
|
|
);
|
|
|
|
check(
|
|
"portrait",
|
|
PORTRAIT,
|
|
(23, 32),
|
|
&[
|
|
(0, 0, [27, 53, 53, 255]),
|
|
(5, 0, [57, 80, 87, 255]),
|
|
(14, 1, [41, 57, 57, 255]),
|
|
(22, 0, [42, 60, 37, 255]),
|
|
(0, 15, [149, 100, 11, 255]),
|
|
(7, 15, [166, 109, 28, 255]),
|
|
(14, 15, [181, 114, 19, 255]),
|
|
(22, 15, [204, 135, 10, 255]),
|
|
(0, 30, [70, 47, 0, 255]),
|
|
(7, 30, [106, 72, 18, 255]),
|
|
(13, 31, [135, 88, 19, 255]),
|
|
(22, 31, [159, 104, 0, 255]),
|
|
],
|
|
);
|
|
|
|
check(
|
|
"alpha",
|
|
ALPHA,
|
|
(32, 32),
|
|
&[
|
|
(1, 0, [227, 76, 54, 0]),
|
|
(10, 0, [147, 102, 114, 45]),
|
|
(19, 0, [130, 156, 130, 94]),
|
|
(31, 0, [192, 168, 23, 0]),
|
|
(0, 15, [232, 65, 49, 162]),
|
|
(10, 14, [142, 87, 106, 255]),
|
|
(20, 14, [141, 152, 119, 255]),
|
|
(31, 14, [231, 191, 50, 148]),
|
|
(0, 31, [255, 33, 10, 0]),
|
|
(11, 31, [213, 65, 76, 137]),
|
|
(20, 31, [209, 109, 64, 137]),
|
|
(31, 31, [255, 137, 0, 0]),
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_truncated_hash() {
|
|
let mut rgba = [0; 32 * 32 * 4];
|
|
for len in 0..ALPHA.len() {
|
|
assert!(decode(&ALPHA[..len], &mut rgba).is_none(), "length {len}");
|
|
}
|
|
}
|