mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-12 21:23:02 +00:00
Actions: admit recorded CAF Current Layer output
Use the explicit cafOutputToCurrentLayer Action Manager binding alongside measured New Layer output. Rectangular sampling remains required; native output may use its proven Current default. Extend existing roundtrip, native-default and pixel/Undo controls without changing renderer or history code. Source-only successor; formatting, compilation and tests remain unrun under native0.
This commit is contained in:
1 parent
d94717c8ca
commit
7e53861e62
3 files changed
+51
-12
No files matched your search
@@ -6,11 +6,12 @@ use super::{D, Descriptor, Map, Value};
|
||||
|
||||
const CMD: &str = "edit.contentAwareFill";
|
||||
const SOURCE: &str = "_atnCafDescriptor";
|
||||
// The measured row names these values; its ellipses are not additional enum bindings.
|
||||
// The measured row bounds these values; its ellipses are not additional enum bindings.
|
||||
const SAMPLING: &[(&str, &str)] = &[("cafSamplingRegionRectangular", "rectangular")];
|
||||
const COLOR: &[(&str, &str)] = &[("cafColorAdaptationDefault", "default")];
|
||||
const ROTATION: &[(&str, &str)] = &[("cafRotationAmountNone", "none")];
|
||||
const OUTPUT: &[(&str, &str)] = &[("cafOutputToNewLayer", "new")];
|
||||
// Current Layer is also explicit in the primary Action Manager example cited in docs/atn.md.
|
||||
const OUTPUT: &[(&str, &str)] = &[("cafOutputToNewLayer", "new"), ("cafOutputToCurrentLayer", "current")];
|
||||
const KEYS: &[&str] = &[
|
||||
"cafSamplingRegion",
|
||||
"cafSampleAllLayers",
|
||||
|
||||
@@ -69,6 +69,11 @@ fn caf_settings_roundtrip_seven_fields_and_boolean_choices() {
|
||||
}
|
||||
cases.push((d, p));
|
||||
}
|
||||
let mut current = base.clone();
|
||||
current.items[6].1 = enm("cafOutput", "cafOutputToCurrentLayer");
|
||||
let mut p = params();
|
||||
p["output"] = json!("current");
|
||||
cases.push((current, p));
|
||||
for (d, p) in cases {
|
||||
let action = load(d.clone());
|
||||
assert_eq!(action.steps, vec![(CMD.into(), p.clone())]);
|
||||
@@ -129,7 +134,6 @@ fn caf_unrepresented_descriptors_are_kept_and_never_partially_play() {
|
||||
(3, "cafRotationAmount", "cafRotationAmountHigh"),
|
||||
(3, "cafRotationAmount", "cafRotationAmountFull"),
|
||||
(3, "cafRotationAmount", "unknown"),
|
||||
(6, "cafOutput", "cafOutputToCurrentLayer"),
|
||||
(6, "cafOutput", "cafOutputToDuplicateLayer"),
|
||||
] {
|
||||
let mut d = base.clone();
|
||||
@@ -170,9 +174,15 @@ fn caf_native_exports_preserve_effective_defaults_and_refuse_unrepresented_optio
|
||||
let a = load(exported(p).unwrap().descriptor.unwrap());
|
||||
assert_eq!(a.steps, vec![(CMD.into(), params())]);
|
||||
}
|
||||
let mut current = params();
|
||||
current["output"] = json!("current");
|
||||
for p in [json!({"sampling":"rectangular"}), current.clone()] {
|
||||
let a = load(exported(p).unwrap().descriptor.unwrap());
|
||||
assert_eq!(a.steps, vec![(CMD.into(), current.clone())]);
|
||||
}
|
||||
for (key, value) in [
|
||||
("sampling", json!("auto")), ("sampling", json!("custom")), ("sampling", json!("unknown")),
|
||||
("output", json!("current")), ("output", json!("duplicate")),
|
||||
("output", json!("duplicate")),
|
||||
("colorAdaptation", json!("none")), ("colorAdaptation", json!("high")), ("colorAdaptation", json!("veryHigh")),
|
||||
("rotationAdaptation", json!("low")), ("rotationAdaptation", json!("medium")),
|
||||
("rotationAdaptation", json!("high")), ("rotationAdaptation", json!("full")),
|
||||
@@ -184,7 +194,7 @@ fn caf_native_exports_preserve_effective_defaults_and_refuse_unrepresented_optio
|
||||
p[key] = value;
|
||||
assert!(exported(p.clone()).is_none(), "{p}");
|
||||
}
|
||||
for p in [json!({}), json!({"sampling":"rectangular"}), json!({"output":"new"}), json!([])] {
|
||||
for p in [json!({}), json!({"output":"new"}), json!([])] {
|
||||
assert!(exported(p.clone()).is_none(), "unrepresented native default: {p}");
|
||||
}
|
||||
}
|
||||
@@ -237,7 +247,7 @@ fn caf_action_matches_native_pixels_and_undo_at_each_depth() {
|
||||
assert!(s.redo());
|
||||
assert_eq!(s.active().unwrap().doc, after);
|
||||
|
||||
// Current-layer native calls still work, although their ATN form is outside this increment.
|
||||
// Current Layer keeps one layer and matches the ordinary native operation as well.
|
||||
let mut current = session(depth);
|
||||
let mut p = params();
|
||||
p["output"] = json!("current");
|
||||
@@ -245,6 +255,32 @@ fn caf_action_matches_native_pixels_and_undo_at_each_depth() {
|
||||
assert_eq!(current.active().unwrap().doc.layers.len(), 1);
|
||||
let center = current.active().unwrap().doc.layers[0].surface().unwrap().rgba(3, 3);
|
||||
assert!(center.iter().all(|v| (*v - 1.0).abs() < 0.01), "{depth}: native Current Layer control failed: {center:?}");
|
||||
let mut recorded = session(depth);
|
||||
let before = recorded.active().unwrap().doc.clone();
|
||||
let source = recorded.active().unwrap().active_layer.unwrap();
|
||||
let past = recorded.active().unwrap().history.past_len();
|
||||
let mut d = descriptor();
|
||||
d.items[6].1 = enm("cafOutput", "cafOutputToCurrentLayer");
|
||||
recorded.actions.list.push(load(d));
|
||||
let result = recorded.execute("actions.play", json!({"action":0})).unwrap();
|
||||
assert_eq!(result["ran"], 1);
|
||||
assert!(result.get("failed").is_none(), "{depth}: {result}");
|
||||
let after = recorded.active().unwrap().doc.clone();
|
||||
assert_eq!(after.layers.len(), before.layers.len());
|
||||
assert_eq!(after.selection, before.selection);
|
||||
assert_eq!(recorded.active().unwrap().active_layer, Some(source));
|
||||
assert_eq!(recorded.active().unwrap().history.past_len(), past + 1);
|
||||
let expected = current.active().unwrap().doc.layers[0].surface().unwrap();
|
||||
let actual = after.layer(source).unwrap().surface().unwrap();
|
||||
for y in 0..8 {
|
||||
for x in 0..8 {
|
||||
assert_eq!(actual.rgba(x, y), expected.rgba(x, y), "{depth}: Current Layer pixel{x},{y}");
|
||||
}
|
||||
}
|
||||
assert!(recorded.undo());
|
||||
assert_eq!(recorded.active().unwrap().doc, before);
|
||||
assert!(recorded.redo());
|
||||
assert_eq!(recorded.active().unwrap().doc, after);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -170,9 +170,11 @@ the reference application.
|
||||
|
||||
### Content-Aware Fill recordings
|
||||
|
||||
`cafWorkspace` maps the measured Rectangular / Default color adaptation / None rotation /
|
||||
New Layer form to `edit.contentAwareFill`, retaining all seven keys and the three booleans:
|
||||
`cafWorkspace` maps Rectangular / Default color adaptation / None rotation with New Layer or
|
||||
Current Layer output to `edit.contentAwareFill`, retaining all seven keys and the three booleans:
|
||||
Sample All Layers, Scale and Mirror. The selection comes from the preceding selection step.
|
||||
New Layer is in the measured reference; Current Layer and the enumeration type IDs are explicit
|
||||
in [Stephen Marsh's published Action Manager example](https://community.adobe.com/questions-712/expand-and-content-aware-fill-functions-are-not-working-via-javascript-1172085).
|
||||
|
||||
| Recorded key, in order | Supported value | Native parameter |
|
||||
|---|---|---|
|
||||
@@ -182,15 +184,15 @@ Sample All Layers, Scale and Mirror. The selection comes from the preceding sele
|
||||
| `cafRotationAmount` | `cafRotationAmountNone` | `rotationAdaptation: "none"` |
|
||||
| `cafScale` | boolean | `scale` |
|
||||
| `cafMirror` | boolean | `mirror` |
|
||||
| `cafOutput` | `cafOutputToNewLayer` | `output: "new"` |
|
||||
| `cafOutput` | `cafOutputToNewLayer`, `cafOutputToCurrentLayer` | `output: "new"`, `"current"` |
|
||||
|
||||
Descriptor types, source identity and key order survive save while its native settings are
|
||||
unchanged. Native export writes the seven keys explicitly; the known native boolean, color
|
||||
adaptation and rotation defaults are supported when sampling is Rectangular and output is New
|
||||
Layer. A native call using Auto or Current Layer defaults cannot yet be exported.
|
||||
adaptation, rotation and Current Layer output defaults are supported when sampling is explicitly
|
||||
Rectangular. A native call using the Auto sampling default cannot yet be exported.
|
||||
|
||||
The reference's ellipses do not establish additional enum forms. Auto/Custom sampling,
|
||||
other adaptation levels, Current/Duplicate Layer output, absent keys, unknown settings and
|
||||
other adaptation levels, Duplicate Layer output, absent keys, unknown settings and
|
||||
malformed or repeated fields remain complete kept steps. Native layer targets, sampling/fill
|
||||
edits and nondefault seeds also refuse export rather than lose their settings. Playback uses
|
||||
the existing native fill and its selection, authorization, job and Undo/Redo behavior. The
|
||||
|
||||
Reference in new issue
Block a user