fix(io): preserve HDR samples when unmatting PSD composites (#106)

This commit is contained in:
MikeeI 2026-10-05 07:00:19 +02:00 committed by GitHub
parent 4af95fa807
commit 7100b0d617
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 12 additions and 2 deletions

View File

@ -167,7 +167,7 @@ pub fn merged_composite(file: &PsdFile) -> Result<Vec<[f32; 4]>, IoError> {
let mut v: [f32; 4] = std::array::from_fn(|i| f32::from(p[i]) / 255.0);
if unmatte {
for c in 0..3 {
v[c] = pixels::unmatte(v[c], v[3], 1.0);
v[c] = pixels::unmatte(v[c], v[3], 1.0).clamp(0.0, 1.0);
}
}
v

View File

@ -139,8 +139,9 @@ pub fn matte(c: f32, a: f32, white: f32) -> f32 {
}
/// Inverse of [`matte`] (returns `white` where alpha is 0).
/// Keep HDR and negative samples; integer encoders own normalized-range clipping.
pub fn unmatte(m: f32, a: f32, white: f32) -> f32 {
if a <= 0.0 { white } else { ((m - white * (1.0 - a)) / a).clamp(0.0, 1.0) }
if a <= 0.0 { white } else { (m - white * (1.0 - a)) / a }
}
/// `items.map(f)` on scoped threads (one per item; callers pass a handful of channels or

View File

@ -418,6 +418,15 @@ fn merged_composite_unmattes_photoshop_white() {
let (d, _) = psd_to_document(&f);
let p = d.layers[0].surface().unwrap().pixel(0, 0);
assert!(p[1] < 0.01 && (p[3] - 128.0 / 255.0).abs() < 1e-6, "{p:?}");
// HDR and negative straight samples must survive the actual F32 PSD import boundary.
let mut hdr = testgen::merged_only(Version::Psd, ColorMode::Rgb, 32, Compression::Raw, 1, 1);
hdr.header.channels = 4;
hdr.image_data =
photocraft_psd::ImageData { compression: Compression::Raw, data: [1.5_f32, 0.25, 0.5, 0.5].into_iter().flat_map(f32::to_be_bytes).collect() };
let imported = import("hdr.psd", &hdr.to_bytes().unwrap()).unwrap().document;
assert_eq!(imported.depth, photocraft_color::SampleType::F32);
assert_eq!(imported.layers[0].surface().unwrap().pixel(0, 0), vec![2.0, -0.5, 0.0, 0.5]);
}
#[test]