Zoomed to 1:1 or past it, the develop canvas showed a smoothed blur
rather than the photograph's pixels, so focus and noise could not be
judged at the magnification meant for judging them.
Two things caused it. The canvas only switched to nearest-neighbour
strictly past 1:1, with a margin, so the 1:1 inspection itself stayed
smooth. And the switch mostly had nothing to act on: the pipeline
rendered a viewport-sized frame at every zoom, so past 1:1 it was the
pipeline doing the enlarging - bilinearly whenever a straightening angle
or lens correction was in the chain - and the detail stage then sharpened
and denoised those invented pixels at radii scaled up to match. The
texture reached the canvas already blurred and was presented 1:1.
Now, from 1:1 on, the visible region is rendered at the source's own
resolution (render::render_size) and the canvas enlarges it with
nearest-neighbour, so the blocks on screen are the pixels an export would
have; it is also less shading. The decision lives in two small
functions, render::magnification and render::shows_source_pixels,
measured in physical pixels like one_to_one_zoom, with a half-percent
tolerance so the inspection zoom counts as 1:1 even where fit() rounded
the other edge. Below 1:1 the render and the smooth filter are unchanged.
develop.rs had grown to 9,327 lines covering everything the develop
session does: opening a photograph, the parameter-row and curve-widget
panel model, mask viewing and editing, mask creation and the rasteriser
that turns a mask stack into GPU arrays, spot repairs, scene
segmentation, framing and zoom, white-balance sampling, rendering and
film choice, and the undo/snapshot history. docs/dev/code-health.md
CH-1 names dr-ui's lack of a view layer as the reason every feature
kept landing in a handful of files; this is the first of the two pure
splits it recommends as easy, no-behaviour-change wins independent of
that larger rework.
The boundaries follow the file's own sections (several were already
marked off with comment headers) and the seams a full read turned up
underneath them -- mask storage/rasterisation turned out to be a
distinct concern from mask viewing and editing, and rows/tabs/curves
from each other, so those split further than the headers alone
suggested. Each module stays under about 1,500 lines. Struct fields
and the handful of helper methods now called from a sibling module
became `pub(super)`, which is strictly narrower than the whole-crate
reachability a single file gave them; nothing gained visibility outside
`develop`. Tests moved with the code they test, including the few
cases where a helper one file's tests needed was itself only defined
in another's -- those became shared fixtures in `mod.rs` alongside the
`headless`/`read_back`/`grey_session` helpers that already worked that
way. `mod.rs` re-exports every item `develop::` callers outside this
module used before, so lib.rs, masks_ui.rs and the rest needed no
changes.