Export the photograph, not the canvas
Zooming the develop view changed the exported file. `Framing::view` is kept out of the sidecar, out of `is_active` and out of `output_size` precisely so that it cannot — but those exclusions keep it out of the *edit*, and an export is a *render*. `visible_rect` deliberately folds the view into the single rect the fused shader's prologue samples, so `render_for_export` inherited it: at 4:1 it wrote the middle of the frame, magnified to fill the file at the full output size, with the detail kernels scaled four times over because `render_scale` folds the view in as well. `render_thumbnail` did the same to the grid. `render_uncropped` already suspends the view for this exact reason, so the fix is its pattern: one `render_the_file` that both file-producing paths go through, composing inside the suspension since the view reaches the shader as a uniform baked at composition time. Restored whatever happens — leaving the graph un-zoomed after a failed export would throw away where the photographer was looking. Nothing caught it because the guard checked the wrong things. `zooming_does_not_change_the_exported_image` asserted the output size and the crop; both held perfectly throughout. Renamed to `zooming_does_not_change_the_size_or_the_crop`, which is what it tests, and the pixels are now guarded where pixels exist. The new test uses a ramp rather than quadrants deliberately: a four-quadrant frame is self-similar under a centred zoom, and the first version of this test passed against the bug because of it. Traces FR-EXP-9, which asks for the full-quality pipeline "regardless of what the display was showing". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -348,9 +348,19 @@ pub struct Framing {
|
||||
/// Which part of the framed image the viewport is looking at.
|
||||
///
|
||||
/// **Not an edit.** Zooming changes what you are inspecting, never what
|
||||
/// the file becomes: it is excluded from [`Self::is_active`], from the
|
||||
/// structure hash, and from the sidecar, so a zoomed view exports exactly
|
||||
/// as an unzoomed one does.
|
||||
/// the file becomes, so it is excluded from [`Self::is_active`], from the
|
||||
/// structure hash, and from the sidecar.
|
||||
///
|
||||
/// **That is not on its own enough to make an export ignore it**, and
|
||||
/// this doc comment used to claim it was. The exclusions keep the view out
|
||||
/// of the *edit* — out of what is saved, out of the output size, out of
|
||||
/// the crop. They cannot keep it out of a *render*, because
|
||||
/// [`Self::visible_rect`] deliberately folds it into the one rect the
|
||||
/// shader samples. Anything composing this framing and rendering it gets
|
||||
/// the zoom; a caller that wants the photograph rather than the canvas
|
||||
/// has to suspend the view first, as `DevelopSession::render_the_file`
|
||||
/// and `render_uncropped` both do. Exporting at 4:1 wrote the middle of
|
||||
/// the frame, magnified, until it did.
|
||||
///
|
||||
/// It lives here rather than in the UI because it composes with the crop
|
||||
/// in the same normalised space — nesting one rect inside the other is a
|
||||
@@ -1252,10 +1262,18 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zooming_does_not_change_the_exported_image() {
|
||||
fn zooming_does_not_change_the_size_or_the_crop() {
|
||||
// The property that makes zoom a viewing tool rather than an edit: it
|
||||
// must not reach the output size or the crop. If it did, exporting
|
||||
// while zoomed would write the zoomed view.
|
||||
// must not reach the output size or the crop.
|
||||
//
|
||||
// **Renamed, because the old name promised more than the body checks
|
||||
// and the gap was where a real bug lived.** "Does not change the
|
||||
// exported image" was read as a guarantee about pixels; it is a
|
||||
// guarantee about two numbers. Both held perfectly while
|
||||
// `render_for_export` was writing the zoomed view at full size,
|
||||
// because the view reaches the render through `visible_rect` and
|
||||
// never through either of these. The pixels are guarded where pixels
|
||||
// exist — `dr-ui`'s `export_ignores_the_viewport`.
|
||||
//
|
||||
// The structure key is deliberately not asserted here — see
|
||||
// `zooming_from_neutral_changes_the_structure_key` for why it must
|
||||
|
||||
Reference in New Issue
Block a user