Graphics: New Layer from File anchors the picture at its own centre

graphics.newFromFile resolved the Motion anchor with the sequence frame size
instead of the imported picture's size, so a picture smaller than the frame
got its anchor at the frame centre (e.g. 960,540 for a 4x2 image). Setting
Motion ▸ Position then moved the wrong point and the picture landed far from
where it was asked to go. place_video_clip now resolves auto points with the
source's own size (Project::source_size), falling back to the frame size.

The new-layer-from-file test checks the anchor is the picture's centre; it
fails before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AJ Depew
2026-10-07 14:35:41 -06:00
co-authored by Claude Opus 5.5
parent 86f3375775
commit 57069293fb
2 changed files with 6 additions and 1 deletions
+3 -1
View File
@@ -124,13 +124,15 @@ pub(crate) fn place_video_clip(
(q.settings.width, q.settings.height, q.settings.frame_rate)
};
let (src, dur) = source(pr, (w, h, rate));
// an imported picture (`graphics.newFromFile`) keeps its own size: centre its anchor in it
let src_size = pr.source_size(src).unwrap_or((w, h));
let t = rate.snap(t);
let dur = dur.max(rate.frame_duration());
let mut ti = pr.make_track_item(src, TrackKind::Video, t, TimeRange::new(Tick::ZERO, dur), rate).ok_or_else(|| bad("graphics.newText", "bad item"))?;
ti.name = name;
ti.effects.extend(extra);
for e in &mut ti.effects {
filmcraft_project::resolve_auto_points(e, (w, h), (w, h));
filmcraft_project::resolve_auto_points(e, (w, h), src_size);
}
let id = ti.id;
let track_id = filmcraft_project::TrackId(pr.alloc_id());
+3
View File
@@ -369,6 +369,9 @@ fn new_layer_from_file_places_the_image_above() {
assert_eq!(it.start, q.settings.frame_rate.snap(t));
let ti = q.video_tracks.iter().position(|tr| tr.id == tid).unwrap();
assert!(q.video_tracks[..ti].iter().any(|tr| tr.item_at(t).is_some()), "above the footage");
// the anchor is the picture's centre, not the frame's, so `position` places the picture
let anchor = it.effect("motion").unwrap().vec2_at("anchor", Tick::ZERO);
assert_eq!((anchor.x, anchor.y), (w as f64 / 2.0, h as f64 / 2.0));
assert_eq!(s.state.selection, vec![clip]);
assert!(s.execute("graphics.newFromFile", json!({})).is_err());
let _ = std::fs::remove_dir_all(&dir);