Skip to content

Import: stills and movies respect their orientation - #803

Closed
pravdomil wants to merge 2 commits into
storytold:mainfrom
pravdomil:import-exif-orientation
Closed

pravdomil wants to merge 2 commits into
storytold:mainfrom
pravdomil:import-exif-orientation

Conversation

@pravdomil

@pravdomil pravdomil commented Oct 11, 2026 •

Copy link
Copy Markdown

What

Photos and phone videos shot with the camera turned imported exactly as stored, lying on their side. They now import the way they are meant to be seen.

Stills (Exif orientation)

  • crates/media/src/probe.rs: probing a still reads the orientation and swaps width and height for the quarter-turn orientations (5–8). A new load_oriented helper decodes a still and applies the rotation or mirroring to the pixels. A missing or invalid tag decodes as stored.
  • crates/media/src/pool.rs, crates/media/src/layered.rs: the still decode (also used by image sequences) and an image embedded in a Photoshop smart object go through load_oriented.

Movies (MP4/MOV rotation)

  • crates/media/src/probe.rs: video_turn reads the video track header (tkhd) through filmcraft-isobmff and takes its rotation, snapped to the nearest quarter turn. Only the rotation is used: mirroring, scaling and offsets in the header are ignored, and other containers have none. Probing swaps width and height (and inverts the pixel aspect) for a quarter turn.
  • crates/media/src/pool.rs: the turn is read once when the file is opened and kept beside its decoder. Decoded frames are turned, including the reduced-resolution path, which asks the decoder for the unturned size.
  • crates/media/src/convert.rs: turned rotates a decoded frame by 90°, 180° or 270°.
  • crates/media/Cargo.toml: new dependency on filmcraft-isobmff (already in the workspace, used by export).

Testing

Run locally on macOS:

  • cargo fmt --all -- --check, cargo clippy -p effectcraft-media --all-targets -- -D warnings, cargo xtask layers: clean
  • cargo test -p effectcraft-media: all pass, including two new tests
    • exif_orientation.rs: a four-colour JPEG built in memory, tagged with each of the eight orientations plus no tag and invalid values; checks size and corner colours. No ffmpeg needed.
    • rotated_mp4_imports_upright in footage.rs: the H.264 fixture with its track header matrix patched to 90°, 180° and 270°; checks the probed size, exact pixels against the unrotated decode, and the reduced-size path. Skips without ffmpeg like its neighbours.
  • A real iPhone HEVC .mov with a 90° rotation: imports as 1440×1920 and its first frame is upright, matching ffmpeg's.

Not run locally: the full cargo xtask ci gate (whole-workspace tests, assets, wasm; the wasm32 target isn't installed here).

Reviewer notes

  • Existing projects: footage already imported from a rotated photo or movie keeps its old, unrotated width and height in the project file, while its frames now decode turned. How the renderer handles that mismatch was not checked; re-importing the file gives the right size.
  • Cost: opening a movie parses its MP4 headers a second time to read the track matrix, and each frame of a rotated movie is copied once more to turn it.

🤖 Generated with Claude Code

pravdomil and others added 2 commits October 11, 2026 14:03
A photo taken with the camera held sideways (or a mirrored scan) imported
as stored, lying on its side. Probing now reports the size the picture is
seen at, and the still and smart-object decodes apply the rotation or
mirroring to the pixels. A missing or invalid tag decodes as stored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A movie shot with a phone held upright stores sideways frames and says so
in its video track header; it imported lying on its side. Probing now
reports the turned size, and decoded frames (full and reduced size) are
turned to match. Only the rotation is used, snapped to a quarter turn;
mirroring, scaling and offsets in the header are ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pravdomil pravdomil changed the title Import: stills respect their Exif orientation Import: stills and movies respect their orientation Oct 11, 2026
@pravdomil pravdomil closed this Oct 11, 2026
@pravdomil
pravdomil deleted the import-exif-orientation branch October 11, 2026 13:47
@pravdomil

Copy link
Copy Markdown
Author

Superseded by #827: the head branch was renamed to claude/import-exif-orientation, which closed this one. Same commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant