diff --git a/crates/engine/src/commands/file_more.rs b/crates/engine/src/commands/file_more.rs index 74a86e1d8..5aade0a75 100644 --- a/crates/engine/src/commands/file_more.rs +++ b/crates/engine/src/commands/file_more.rs @@ -1035,7 +1035,7 @@ pub fn specs() -> Vec { "Main...", ["File", "Interpret Footage"], Some("Cmd+Alt+G"), - "{items?, frameRate?: fps|\"file\", alpha?: straight|premultiplied|ignore|guess, guessAlpha?, matteColor?, invertAlpha?, loop?, pixelAspect?, fields?: off|upper|lower, colorProfile?: srgb|rec709|rec2020|p3|auto, linearLight?, preserveRgb? (the file's values unconverted), overrideStart?: bool (false: Use Source File Timecode), startTimecode?: timecode|frame (Override Start)}", + "{items?|item?, frameRate?: fps|\"file\", alpha?: straight|premultiplied|ignore|guess, guessAlpha?, matteColor?|premulColor?, invertAlpha?, loop?, pixelAspect?, fields?: off|upper|lower, colorProfile?: srgb|rec709|rec2020|p3|auto, linearLight?, preserveRgb? (the file's values unconverted), overrideStart?: bool (false: Use Source File Timecode), startTimecode?: timecode|frame (Override Start)}", has_footage_selection, interpret ), @@ -1053,7 +1053,7 @@ pub fn specs() -> Vec { "Apply Interpretation", ["File", "Interpret Footage"], Some("Cmd+Alt+V"), - "{items?}", + "{items?|item?}", has_interpretation, apply_interpretation ), @@ -1084,7 +1084,7 @@ pub fn specs() -> Vec { has_footage_selection, replace_with_solid ), - cmd!("file.reloadFootage", "Reload Footage", ["File"], Some("Cmd+Alt+L"), "{items?}", has_footage_selection, reload), + cmd!("file.reloadFootage", "Reload Footage", ["File"], Some("Cmd+Alt+L"), "{items?|item?}", has_footage_selection, reload), cmd!("file.revealInFinder", "Reveal in Finder", ["File"], None, "{item?}", has_footage_selection, reveal_in_finder), ] } diff --git a/crates/engine/src/commands/proxy.rs b/crates/engine/src/commands/proxy.rs index b7d644b94..d15f93730 100644 --- a/crates/engine/src/commands/proxy.rs +++ b/crates/engine/src/commands/proxy.rs @@ -229,7 +229,7 @@ pub fn specs() -> Vec { "Proxy...", ["File", "Interpret Footage"], None, - "{items?|item?, alpha?, matteColor?, invertAlpha?, frameRate?, loop?, pixelAspect?, fields?, colorProfile?, linearLight?}", + "{items?|item?, alpha?, guessAlpha?, matteColor?|premulColor?, invertAlpha?, frameRate?, loop?, pixelAspect?, fields?, colorProfile?, linearLight?, preserveRgb?, overrideStart?, startTimecode? (as file.interpretFootage)}", has_proxy, interpret_proxy ), diff --git a/crates/engine/src/tests_proxy.rs b/crates/engine/src/tests_proxy.rs index 82cd1dcfd..04372685f 100644 --- a/crates/engine/src/tests_proxy.rs +++ b/crates/engine/src/tests_proxy.rs @@ -187,6 +187,38 @@ fn interpret_proxy_settings_apply_to_the_proxy() { assert_eq!(f.alpha, AlphaMode::Straight, "the main footage keeps its interpretation"); } +/// Agents and the control channel run commands through `execute_checked`, which refuses keys a +/// params doc does not list. The Interpret Footage commands list every key they read. +#[test] +fn interpret_commands_accept_their_keys_when_checked() { + let mut s = session(); + let mov = import(&mut s, "/m/lines.mov"); + let b = import(&mut s, "/m/red16.png"); + s.execute("file.setProxy", json!({"item": mov.0, "path": "/m/lines.mov"})).unwrap(); + s.execute("file.setProxy", json!({"item": b.0, "path": "/m/matte_black.png"})).unwrap(); + s.execute_checked("file.interpretProxy", json!({"item": mov.0, "preserveRgb": true, "overrideStart": true, "startTimecode": 25})).unwrap(); + let px = s.project.item(mov).unwrap().proxy.clone().unwrap().footage; + assert!(px.preserve_rgb); + assert_eq!(px.start_timecode, Some(25)); + s.execute_checked("file.interpretProxy", json!({"item": mov.0, "overrideStart": false})).unwrap(); + assert_eq!(s.project.item(mov).unwrap().proxy.as_ref().unwrap().footage.start_timecode, None); + s.execute_checked("file.interpretProxy", json!({"item": b.0, "guessAlpha": true})).unwrap(); + assert_eq!(s.project.item(b).unwrap().proxy.as_ref().unwrap().footage.alpha, AlphaMode::Premultiplied); + s.execute_checked("file.interpretProxy", json!({"item": b.0, "premulColor": [1.0, 0.0, 0.0]})).unwrap(); + assert_eq!(s.project.item(b).unwrap().proxy.as_ref().unwrap().footage.premul_color, [1.0, 0.0, 0.0]); + // `item` names one footage item, as `items` names several. + s.execute_checked("file.interpretFootage", json!({"item": b.0, "invertAlpha": true, "premulColor": [0.0, 1.0, 0.0]})).unwrap(); + s.execute_checked("file.rememberInterpretation", json!({"item": b.0})).unwrap(); + s.execute_checked("file.applyInterpretation", json!({"item": mov.0})).unwrap(); + let f = match &s.project.item(mov).unwrap().kind { + ItemKind::Footage(f) => f.clone(), + _ => panic!("not footage"), + }; + assert!(f.invert_alpha); + assert_eq!(f.premul_color, [0.0, 1.0, 0.0]); + assert_eq!(s.execute_checked("file.reloadFootage", json!({"item": mov.0})).unwrap()["reloaded"], 1); +} + /// Separate Fields: each field becomes a frame at twice the frame rate, the other field's lines /// interpolated; the dominant field comes first. #[test]