From 875d9593b64b33b0f42d3f1bd34d6a818e68dc45 Mon Sep 17 00:00:00 2001 From: Kanyin Cai Date: Sat, 21 Mar 2026 13:35:13 +0100 Subject: [PATCH] test(02-01): add linear-light correctness unit test to yazi-adapter --- .planning/ROADMAP.md | 9 +++++--- yazi-adapter/src/image.rs | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index fe9b7239..f3e0bf27 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -35,7 +35,7 @@ Decimal phases appear between their surrounding integers in numeric order. **Plans:** 1 plan Plans: -- [ ] 01-01-PLAN.md — Replace resize pipeline with linear-light fast_image_resize (dependency + code + verification) +- [x] 01-01-PLAN.md — Replace resize pipeline with linear-light fast_image_resize (dependency + code + verification) ### Phase 2: Verification **Goal**: The implementation is confirmed correct across all image types, protocols, and edge cases, with at least one automated correctness test @@ -46,7 +46,10 @@ Plans: 2. RGBA PNG with transparency displays without color fringing on transparent edges in IIP/WezTerm 3. EXIF-rotated JPEG (phone photo) previews with correct orientation and no quality regression 4. `cargo test --workspace` passes with the new test included -**Plans**: TBD +**Plans:** 1 plan + +Plans: +- [ ] 02-01-PLAN.md — Add linear-light correctness unit test and visual verification checklist ## Progress @@ -56,4 +59,4 @@ Phases execute in numeric order: 1 -> 2 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Implementation | 0/1 | Planned | - | -| 2. Verification | 0/TBD | Not started | - | +| 2. Verification | 0/1 | Planned | - | diff --git a/yazi-adapter/src/image.rs b/yazi-adapter/src/image.rs index e1b9587c..abac7d09 100644 --- a/yazi-adapter/src/image.rs +++ b/yazi-adapter/src/image.rs @@ -197,3 +197,49 @@ impl Image { } } } + +#[cfg(test)] +mod tests { + use super::*; + use image::RgbImage; + + #[test] + fn test_linear_light_gray_midpoint() { + // 50/50 mix of black and white pixels in a 4x4 checkerboard pattern. + // Averaging in sRGB space gives (0+255)/2 = 128. + // Averaging in linear-light space gives (0.0+1.0)/2 = 0.5, + // which maps back to sRGB ~186 via the gamma curve. + let black = image::Rgb([0u8, 0, 0]); + let white = image::Rgb([255u8, 255, 255]); + let mut img = RgbImage::new(4, 4); + for y in 0..4 { + for x in 0..4 { + let pixel = if (x + y) % 2 == 0 { white } else { black }; + img.put_pixel(x, y, pixel); + } + } + let img = DynamicImage::from(img); + + // Downscale to 1x1 using Lanczos3 (default filter) + let alg = ResizeAlg::Convolution(fast_image_resize::FilterType::Lanczos3); + let result = Image::fir_resize(img, 1, 1, alg).expect("fir_resize should succeed"); + + // Extract the single pixel + let rgb = result.to_rgb8(); + let pixel = rgb.get_pixel(0, 0); + + // Linear-light-correct downscaling of a 50/50 black+white checkerboard + // should yield ~186, because linear 0.5 maps to sRGB ~186. + // + // If we got ~128, the linearization pipeline is broken (sRGB-space averaging). + let tolerance = 5u8; + let expected = 186u8; + for (i, &channel) in pixel.0.iter().enumerate() { + assert!( + channel.abs_diff(expected) <= tolerance, + "channel {i}: expected ~{expected} (+/-{tolerance}), got {channel}. \ + A value near 128 means sRGB linearization is not working." + ); + } + } +}