diff --git a/crates/psd/src/memory_tests.rs b/crates/psd/src/memory_tests.rs index 97b7f5be..108046b6 100644 --- a/crates/psd/src/memory_tests.rs +++ b/crates/psd/src/memory_tests.rs @@ -40,7 +40,7 @@ impl Psd { Ok(self.ref_samples(&raw, w, h)) } - fn ref_samples(&self, raw: &[u8], w: usize, h: usize) -> Vec { + pub(crate) fn ref_samples(&self, raw: &[u8], w: usize, h: usize) -> Vec { match self.depth { 1 => { let rowb = w.div_ceil(8); @@ -55,13 +55,29 @@ impl Psd { out } 16 => raw.as_chunks::<2>().0.iter().take(w * h).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(), - 32 => raw.as_chunks::<4>().0.iter().take(w * h).map(|c| f32::from_be_bytes([c[0], c[1], c[2], c[3]])).collect(), + // As the previous decoder after the non-finite fix: NaN reads as 0, +inf as 1, -inf as 0. + 32 => raw + .as_chunks::<4>() + .0 + .iter() + .take(w * h) + .map(|c| { + let v = f32::from_be_bytes([c[0], c[1], c[2], c[3]]); + if v.is_nan() || v == f32::NEG_INFINITY { + 0.0 + } else if v == f32::INFINITY { + 1.0 + } else { + v + } + }) + .collect(), _ => raw.iter().take(w * h).map(|&b| b as f32 / 255.0).collect(), } } /// Convert colour channels (in the document's mode) to RGB. - fn ref_to_rgb(&self, ch: &[Option>], i: usize) -> [f32; 3] { + pub(crate) fn ref_to_rgb(&self, ch: &[Option>], i: usize) -> [f32; 3] { let g = |k: usize| ch.get(k).and_then(|c| c.as_ref()).map_or(0.0, |c| c[i]); let rgb = match self.mode { ColorMode::Rgb => [g(0), g(1), g(2)], diff --git a/crates/psd/src/tests_opt.rs b/crates/psd/src/tests_opt.rs index 1ffb565c..f129480c 100644 --- a/crates/psd/src/tests_opt.rs +++ b/crates/psd/src/tests_opt.rs @@ -76,7 +76,7 @@ fn ref_decode_channel(p: &Psd, offset: usize, len: usize, w: usize, h: usize) -> } c => return Err(Error::Unsupported(format!("compression {c}"))), }; - Ok(p.samples(&raw, w, h)) + Ok(p.ref_samples(&raw, w, h)) } fn ref_composite(p: &Psd) -> Result { @@ -92,7 +92,7 @@ fn ref_composite(p: &Psd) -> Result { match comp { 0 => { for pl in planes.iter_mut().take(want) { - *pl = Some(p.samples(r.bytes(rowb * h)?, w, h)); + *pl = Some(p.ref_samples(r.bytes(rowb * h)?, w, h)); } } 1 => { @@ -105,7 +105,7 @@ fn ref_composite(p: &Psd) -> Result { for row in 0..h { unpack_bits(r.bytes(counts[c * h + row])?, rowb, &mut out)?; } - *pl = Some(p.samples(&out, w, h)); + *pl = Some(p.ref_samples(&out, w, h)); } } 2 | 3 => { @@ -116,7 +116,7 @@ fn ref_composite(p: &Psd) -> Result { if comp == 3 { ref_unpredict(p.depth, &mut plane, w, h); } - *pl = Some(p.samples(&plane, w, h)); + *pl = Some(p.ref_samples(&plane, w, h)); } } c => return Err(Error::Unsupported(format!("compression {c}"))), @@ -124,7 +124,7 @@ fn ref_composite(p: &Psd) -> Result { let alpha = if p.merged_alpha && nch > cc { planes[cc].take() } else { None }; let mut data = Vec::with_capacity(w * h); for i in 0..w * h { - let [r, g, b] = p.to_rgb(&planes, i); + let [r, g, b] = p.ref_to_rgb(&planes, i); let a = alpha.as_ref().map_or(1.0, |a| a[i]); data.push([r, g, b, a]); } @@ -175,7 +175,7 @@ fn ref_layer_pixels(p: &Psd, index: usize, canvas: bool) -> Result { let i = y * sw + x; let (rgb, a) = match fill { Some(f) if !l.has_pixels() => (f, 1.0), - _ => (p.to_rgb(&planes, i), alpha.as_ref().map_or(1.0, |a| a[i])), + _ => (p.ref_to_rgb(&planes, i), alpha.as_ref().map_or(1.0, |a| a[i])), }; out[dy * ow + dx] = [rgb[0], rgb[1], rgb[2], a]; } @@ -463,7 +463,7 @@ fn raw_planes_are_borrowed_and_zip_planes_are_unpredicted_in_place() { let c = q.layers[0].channels[0]; let mut r = Reader::at(&q.data, c.offset); let comp = r.u16().unwrap(); - let plane = q.plane_bytes(comp, &mut r, 40, 30).unwrap(); + let plane = q.plane_bytes(comp, &mut r, 40, 30, &mut Budget::new(u64::MAX)).unwrap(); let Cow::Borrowed(b) = plane else { panic!("raw plane was copied") }; let file = q.data.as_ptr_range(); assert!(file.contains(&b.as_ptr()) && b.len() == 1200);