mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-13 23:17:30 +00:00
PSD: take the integration branch's adapted non-finite test and psd_import formatting (#1149)
The six PSD PRs merged one by one leave #1131's test calling samples()/to_rgb(), which #1139 replaced; vangel76's integration draft #1149 has the adapted version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
02c412b835
commit
eb2b734059
2 files changed
+61
-63
No files matched your search
@@ -111,16 +111,13 @@ struct Ctx<'a> {
|
||||
pub fn import(proj: &mut Project, psd: &Psd, path: &str, name: &str, retain: bool, rate: FrameRate, duration: Tick) -> PsdImport {
|
||||
let folder = proj.add_item(&format!("{name} Layers"), Label::Yellow, None, ItemKind::Folder);
|
||||
let mut cx = Ctx { psd, path, retain, folder, rate, duration, items: vec![], warnings: vec![] };
|
||||
cx.warnings.extend(psd.warnings.iter().cloned());
|
||||
let (tree, flattened) = psd.tree_report();
|
||||
if flattened > 0 {
|
||||
cx.warnings.push(format!("{flattened} group(s) nested deeper than {} levels were flattened into their parent", effectcraft_psd::MAX_GROUP_DEPTH));
|
||||
}
|
||||
cx.warnings.extend(psd.warnings.iter().cloned());
|
||||
let comp = if psd.layers.is_empty() && !psd.warnings.is_empty() {
|
||||
flattened_comp(proj, &mut cx, name)
|
||||
} else {
|
||||
build_comp(proj, &mut cx, name, &tree, None)
|
||||
};
|
||||
let comp =
|
||||
if psd.layers.is_empty() && !psd.warnings.is_empty() { flattened_comp(proj, &mut cx, name) } else { build_comp(proj, &mut cx, name, &tree, None) };
|
||||
PsdImport { comp, folder, items: cx.items, warnings: cx.warnings }
|
||||
}
|
||||
|
||||
|
||||
+58
-57
@@ -340,9 +340,10 @@ fn non_finite_32_bit_samples_become_finite() {
|
||||
d.layers = vec![WLayer::solid("L", Rect::new(0, 0, 4, 4), [0.5, 0.5, 0.5, 1.0])];
|
||||
let p = Psd::parse(write(&d)).unwrap();
|
||||
let raw: Vec<u8> = [f32::NAN, f32::INFINITY, f32::NEG_INFINITY, 0.25].iter().flat_map(|v| v.to_be_bytes()).collect();
|
||||
let s = p.samples(&raw, 4, 1);
|
||||
let mut s = vec![f32::NAN; 4];
|
||||
p.for_each_sample(&raw, 4, 1, |i, v| s[i] = v);
|
||||
assert_eq!(s, vec![0.0, 1.0, 0.0, 0.25]);
|
||||
assert!(p.to_rgb(&[Some(s.clone()), Some(s.clone()), Some(s)], 1).iter().all(|v| v.is_finite()));
|
||||
assert!(p.rgb_from([s[1], s[1], s[1], 0.0]).iter().all(|v| v.is_finite()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -352,6 +353,61 @@ fn rect_new_near_i32_max_saturates() {
|
||||
assert!(r.is_empty());
|
||||
}
|
||||
|
||||
fn find(bytes: &[u8], needle: &[u8]) -> usize {
|
||||
bytes.windows(needle.len()).position(|w| w == needle).expect("needle present")
|
||||
}
|
||||
|
||||
/// The second layer record's signature overwritten.
|
||||
fn bad_signature() -> Vec<u8> {
|
||||
let mut bytes = write(&doc_with_layers(8, ColorMode::Rgb, true));
|
||||
let at = find(&bytes, b"8BIMmul ");
|
||||
bytes[at] = b'X';
|
||||
bytes
|
||||
}
|
||||
|
||||
/// The first channel of the first layer claims more data than the file holds.
|
||||
fn bad_channel_length() -> Vec<u8> {
|
||||
let mut bytes = write(&doc_with_layers(8, ColorMode::Rgb, true));
|
||||
let at = find(&bytes, b"8BIMnorm");
|
||||
let first_len = at - 4 * 6 + 2;
|
||||
bytes[first_len..first_len + 4].copy_from_slice(&0x7fff_fff0u32.to_be_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn damaged_layer_section_keeps_the_merged_image() {
|
||||
let good = Psd::parse(write(&doc_with_layers(8, ColorMode::Rgb, true))).unwrap();
|
||||
assert!(good.warnings.is_empty() && good.layers.len() == 3);
|
||||
let want = good.composite().unwrap();
|
||||
for bytes in [bad_signature(), bad_channel_length()] {
|
||||
let p = Psd::parse(bytes).unwrap();
|
||||
assert!(p.layers.is_empty());
|
||||
assert_eq!(p.warnings.len(), 1, "{:?}", p.warnings);
|
||||
assert!(p.warnings[0].contains("Layers could not be read"));
|
||||
assert_eq!((p.width, p.height), (40, 30));
|
||||
let got = p.composite().unwrap();
|
||||
assert_eq!(got.data, want.data);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_damage_and_missing_merged_image_still_fail() {
|
||||
let good = write(&doc_with_layers(8, ColorMode::Rgb, true));
|
||||
// Zero width.
|
||||
let mut b = good.clone();
|
||||
b[18..22].copy_from_slice(&0u32.to_be_bytes());
|
||||
assert!(Psd::parse(b).is_err());
|
||||
// Unknown colour mode.
|
||||
let mut b = good.clone();
|
||||
b[24..26].copy_from_slice(&99u16.to_be_bytes());
|
||||
assert!(Psd::parse(b).is_err());
|
||||
// Damaged layers and no merged image at all: nothing to fall back to.
|
||||
let end = Psd::parse(good).unwrap().merged_offset;
|
||||
let mut b = bad_signature();
|
||||
b.truncate(end);
|
||||
assert!(Psd::parse(b).is_err());
|
||||
}
|
||||
|
||||
/// A ZIP plane body for the decoder: the plane delta-coded per row when `predict`.
|
||||
fn zip_body(raw: &[u8], w: usize, depth: u16, predict: bool) -> Vec<u8> {
|
||||
if !predict {
|
||||
@@ -434,58 +490,3 @@ fn rle_composite_matches_the_raw_one() {
|
||||
assert_eq!(rle.layer_pixels(2, true).unwrap().data, raw.layer_pixels(2, true).unwrap().data, "{depth} bit");
|
||||
}
|
||||
}
|
||||
|
||||
fn find(bytes: &[u8], needle: &[u8]) -> usize {
|
||||
bytes.windows(needle.len()).position(|w| w == needle).expect("needle present")
|
||||
}
|
||||
|
||||
/// The second layer record's signature overwritten.
|
||||
fn bad_signature() -> Vec<u8> {
|
||||
let mut bytes = write(&doc_with_layers(8, ColorMode::Rgb, true));
|
||||
let at = find(&bytes, b"8BIMmul ");
|
||||
bytes[at] = b'X';
|
||||
bytes
|
||||
}
|
||||
|
||||
/// The first channel of the first layer claims more data than the file holds.
|
||||
fn bad_channel_length() -> Vec<u8> {
|
||||
let mut bytes = write(&doc_with_layers(8, ColorMode::Rgb, true));
|
||||
let at = find(&bytes, b"8BIMnorm");
|
||||
let first_len = at - 4 * 6 + 2;
|
||||
bytes[first_len..first_len + 4].copy_from_slice(&0x7fff_fff0u32.to_be_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn damaged_layer_section_keeps_the_merged_image() {
|
||||
let good = Psd::parse(write(&doc_with_layers(8, ColorMode::Rgb, true))).unwrap();
|
||||
assert!(good.warnings.is_empty() && good.layers.len() == 3);
|
||||
let want = good.composite().unwrap();
|
||||
for bytes in [bad_signature(), bad_channel_length()] {
|
||||
let p = Psd::parse(bytes).unwrap();
|
||||
assert!(p.layers.is_empty());
|
||||
assert_eq!(p.warnings.len(), 1, "{:?}", p.warnings);
|
||||
assert!(p.warnings[0].contains("Layers could not be read"));
|
||||
assert_eq!((p.width, p.height), (40, 30));
|
||||
let got = p.composite().unwrap();
|
||||
assert_eq!(got.data, want.data);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_damage_and_missing_merged_image_still_fail() {
|
||||
let good = write(&doc_with_layers(8, ColorMode::Rgb, true));
|
||||
// Zero width.
|
||||
let mut b = good.clone();
|
||||
b[18..22].copy_from_slice(&0u32.to_be_bytes());
|
||||
assert!(Psd::parse(b).is_err());
|
||||
// Unknown colour mode.
|
||||
let mut b = good.clone();
|
||||
b[24..26].copy_from_slice(&99u16.to_be_bytes());
|
||||
assert!(Psd::parse(b).is_err());
|
||||
// Damaged layers and no merged image at all: nothing to fall back to.
|
||||
let end = Psd::parse(good).unwrap().merged_offset;
|
||||
let mut b = bad_signature();
|
||||
b.truncate(end);
|
||||
assert!(Psd::parse(b).is_err());
|
||||
}
|
||||
Reference in new issue
Block a user