Import: only dropped files default to stills; scripts and agents naming a frame still get its run (#431)
The UI behaves as in After Effects (the Import dialog's Sequence checkbox starts off, dropped files are stills, dropped folders make sequences), but file.import without sequence or drag keeps importing a numbered still's run, so existing scripts and agents keep working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
This commit is contained in:
parent
8b42f970b6
commit
5e2c7560d6
|
|
@ -688,7 +688,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
|||
"File...",
|
||||
["File", "Import"],
|
||||
Some("Cmd+I"),
|
||||
"{paths: [string] (files or folders), sequence?: bool (the Sequence checkbox: true imports numbered stills of one run as one image sequence, one picked file bringing its whole run and several picked files that range; by default picked files import as stills and folders' numbered stills as sequences; false imports a folder's files individually), alphabetical?: bool (Force Alphabetical Order: every image of that type in the folder, by name), frameRate?: fps (image sequences; default Settings ▸ Import ▸ Sequence Footage), importAs?: footage|composition|compositionLayerSizes (Photoshop, PDF, Illustrator and EPS files), layer?: name|index (footage of one Photoshop layer), page?: number from 1 (PDF / Illustrator page), drag?: bool (dropped files: Settings ▸ Import ▸ Default Drag Import As), addToComp?: bool (also add them to the active comp, at time?, index?, position? as in layer.addItem), background?: bool (probe the files in a background job, jobs.list / jobs.wait; returns {job})}",
|
||||
"{paths: [string] (files or folders), sequence?: bool (the Sequence checkbox: true imports numbered stills of one run as one image sequence, one picked file bringing its whole run and several picked files that range; default: a numbered still brings its run, except dropped files (drag), which import as stills as in After Effects; folders' runs import as sequences; false imports stills and a folder's files individually), alphabetical?: bool (Force Alphabetical Order: every image of that type in the folder, by name), frameRate?: fps (image sequences; default Settings ▸ Import ▸ Sequence Footage), importAs?: footage|composition|compositionLayerSizes (Photoshop, PDF, Illustrator and EPS files), layer?: name|index (footage of one Photoshop layer), page?: number from 1 (PDF / Illustrator page), drag?: bool (dropped files: Settings ▸ Import ▸ Default Drag Import As; files import as stills unless sequence), addToComp?: bool (also add them to the active comp, at time?, index?, position? as in layer.addItem), background?: bool (probe the files in a background job, jobs.list / jobs.wait; returns {job})}",
|
||||
always,
|
||||
import_cmd
|
||||
),
|
||||
|
|
|
|||
|
|
@ -42,15 +42,17 @@ impl SequenceOptions {
|
|||
SequenceOptions { sequence, folders: sequence, alphabetical: flag("alphabetical").unwrap_or(false) }
|
||||
}
|
||||
|
||||
/// `file.import`'s options, as in After Effects: picked or dropped files import as stills
|
||||
/// unless `sequence: true` (the Import dialog's "<format> Sequence" checkbox, which is off
|
||||
/// unless ticked), while a folder's numbered stills import as sequences unless
|
||||
/// `sequence: false` (Alt-drag of a folder).
|
||||
/// `file.import`'s options. Dropped files (`drag: true`) import as stills, as in After
|
||||
/// Effects, while a folder's numbered stills import as sequences unless `sequence: false`
|
||||
/// (Alt-drag of a folder). The Import dialog passes its "<format> Sequence" checkbox (off
|
||||
/// unless ticked) as `sequence`. Without `sequence` or `drag` (scripts, agents) a numbered
|
||||
/// still brings its run, as it always has.
|
||||
pub fn for_import(p: &serde_json::Value) -> SequenceOptions {
|
||||
let flag = |k: &str| p.get(k).and_then(serde_json::Value::as_bool);
|
||||
let (sequence, alphabetical) = (flag("sequence"), flag("alphabetical").unwrap_or(false));
|
||||
let dropped = flag("drag").unwrap_or(false);
|
||||
// Force Alphabetical Order is part of the Sequence option.
|
||||
SequenceOptions { sequence: sequence.unwrap_or(alphabetical), folders: sequence.unwrap_or(true), alphabetical }
|
||||
SequenceOptions { sequence: sequence.unwrap_or(alphabetical || !dropped), folders: sequence.unwrap_or(true), alphabetical }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,11 +97,15 @@ fn numbered_stills_import_as_stills_by_default() {
|
|||
let r = s.execute("file.import", json!({"paths": [at(&dir, "shot_0002.png")], "drag": true})).unwrap();
|
||||
let (name, f) = footage(&s, &r["items"][0]);
|
||||
assert_eq!((name.as_str(), f.kind), ("shot_0002.png", FootageKind::Still));
|
||||
let r = s.execute("file.import", json!({"paths": [at(&dir, "shot_0001.png"), at(&dir, "shot_0004.png")]})).unwrap();
|
||||
let r = s.execute("file.import", json!({"paths": [at(&dir, "shot_0001.png"), at(&dir, "shot_0004.png")], "drag": true})).unwrap();
|
||||
assert_eq!(r["items"].as_array().unwrap().len(), 2, "{r}");
|
||||
let r = s.execute("file.import", json!({"paths": [dir.clone()], "drag": true})).unwrap();
|
||||
let (name, f) = footage(&s, &r["items"][0]);
|
||||
assert_eq!((name.as_str(), f.kind), ("shot_[0001-0005].png", FootageKind::Sequence));
|
||||
// Scripts and agents naming one frame without `sequence` still get its run.
|
||||
let r = s.execute("file.import", json!({"paths": [at(&dir, "shot_0003.png")]})).unwrap();
|
||||
let (_, f) = footage(&s, &r["items"][0]);
|
||||
assert_eq!(f.kind, FootageKind::Sequence);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -251,10 +251,10 @@ build real projects through these interfaces; they are worked examples of everyt
|
|||
then `keys.velocity {"outSpeed":0,"outInfluence":33.33}`.
|
||||
* **Gradients**: `set_property {"path":"contents/gfill/colors","value":["#0080ff","#ffff00"]}` or
|
||||
`{"colors":[[0,"#0080ff"],[1,[1,1,0]]],"opacities":[[0,1],[1,0.5]]}`.
|
||||
* **Image sequences**: `file.import {"paths":["/r/shot_0001.png"], "sequence": true}` imports the
|
||||
file's whole numbered run as one item (several picked frames: that range; a folder, even without
|
||||
`sequence`: each run in it; without `sequence` picked files import as stills, as in After
|
||||
Effects; `"alphabetical": true`: Force Alphabetical Order, the files
|
||||
* **Image sequences**: `file.import {"paths":["/r/shot_0001.png"]}` imports the file's whole
|
||||
numbered run as one item (several picked frames: that range; a folder: each run in it;
|
||||
`"sequence": false`: one still; dropped files, `"drag": true`, import as stills unless
|
||||
`"sequence": true`, as in After Effects; `"alphabetical": true`: Force Alphabetical Order, the files
|
||||
play one after another) at `frameRate` or 30 fps (Settings ▸ Import). Missing frames show
|
||||
colour bars, as in After Effects. `file.interpretFootage {"items":[id], "frameRate":12,
|
||||
"startTimecode":1001}` conforms them and sets Override Start (the item and layers that ran to its end get the new
|
||||
|
|
|
|||
|
|
@ -52,9 +52,11 @@ Effects does, so every other frame stays at its number. Render or copy the missi
|
|||
folder and choose File ▸ Reload Footage to fill the gaps.
|
||||
|
||||
Agents: `file.import {"paths": ["/shots/shot_0001.png"], "sequence": true, "frameRate": 24}`.
|
||||
Without `sequence`, picked files import as stills and a folder's numbered runs as sequences;
|
||||
Without `sequence`, a numbered file brings its whole run and a folder's numbered runs import as
|
||||
sequences, except dropped files (`"drag": true`), which import as stills as in After Effects.
|
||||
`"sequence": true` is the Sequence option (one file brings its whole run), `"sequence": false`
|
||||
imports a folder's files one by one, and `"alphabetical": true` is Force Alphabetical Order.
|
||||
imports stills and a folder's files one by one, and `"alphabetical": true` is Force Alphabetical
|
||||
Order.
|
||||
|
||||
## Interpret Footage
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue