Say which camera profile a photograph renders through, and offer to copy it
The info panel gains a line under the lens: "Adobe Standard · in the file", the .dcp it came from, "· off" when the photographer switched it off, or "No camera profile · matrix only" — the ordinary case for a CR2, worded as a fact rather than a failure. A DNG whose embedded profile may be copied, for a body with no installed profile, also gets "Use this profile for every Canon EOS 6D →", which saves it into the profiles directory; the body's CR2s render through it from their next decode. The profiles directory is <data>/profiles, read at start-up on desktop and Android before anything decodes. The library open path never set the lens line; it now sets both. Labels: Camera Profile, Use Profile, Look Amount.
This commit is contained in:
@@ -324,6 +324,13 @@ pub(crate) fn open_session(
|
||||
// the capture date because of this line; before it, the same photograph
|
||||
// exported from the grid kept them and exported from develop did not.
|
||||
session.set_source_metadata(meta.clone());
|
||||
// TRACES: FR-DEV-3e
|
||||
// The embedded camera profile, read again from the header, for the info
|
||||
// panel's offer to copy it. Only a DNG carries one; the read is the
|
||||
// header's IFDs, not the photosites.
|
||||
if dr_decode::probe(bytes) != Some(dr_types::Format::Jpeg) {
|
||||
session.set_embedded_profile(dr_decode::dcp::embedded_in(bytes));
|
||||
}
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
@@ -1194,6 +1201,19 @@ pub fn run(paths: Vec<PathBuf>) -> Result<()> {
|
||||
log::info!("gpu opened in {} ms", launch_began.elapsed().as_millis());
|
||||
|
||||
let window = init_window(&gpu)?;
|
||||
|
||||
// TRACES: FR-DEV-3e
|
||||
// The installed camera profiles, before anything decodes (D20). A
|
||||
// directory of a few `.dcp` files, each a couple of hundred kilobytes,
|
||||
// so read here rather than deferred: a photograph opened before a
|
||||
// background load finished would render without its profile once and
|
||||
// with it the next time.
|
||||
let profiles_began = std::time::Instant::now();
|
||||
dr_decode::dcp::set_profiles_directory(library::data_root().join("profiles"));
|
||||
log::info!(
|
||||
"camera profiles read in {} ms",
|
||||
profiles_began.elapsed().as_millis()
|
||||
);
|
||||
wire_inference_status(&window);
|
||||
wire_diagnostics(&window, &gpu);
|
||||
|
||||
@@ -1246,6 +1266,7 @@ pub fn run(paths: Vec<PathBuf>) -> Result<()> {
|
||||
let index = Rc::new(RefCell::new(0usize));
|
||||
// The current develop session, if the file yielded sensor data.
|
||||
let session: Rc<RefCell<Option<DevelopSession>>> = Rc::new(RefCell::new(None));
|
||||
wire_profile_offer(&window, &session);
|
||||
|
||||
// TRACES: FR-PLAT-AND-5
|
||||
// The GPU tier — the first thing given back under memory pressure, and on
|
||||
@@ -1479,6 +1500,43 @@ fn init_window(gpu: &Option<dr_gpu::GpuContext>) -> Result<AppWindow> {
|
||||
/// What the models run on. Re-read every two seconds because the answer
|
||||
/// changes twice after launch — when the probe reports and as each
|
||||
/// engine lands — and the page is open for longer than either takes.
|
||||
/// TRACES: FR-DEV-3e
|
||||
/// The info panel's camera profile line and its offer, for the session just
|
||||
/// opened — or cleared, for none.
|
||||
fn show_camera_profile(window: &AppWindow, session: Option<&DevelopSession>) {
|
||||
window.global::<Capture>().set_profile(
|
||||
session
|
||||
.map(DevelopSession::profile_summary)
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
);
|
||||
window.global::<ProfileOffer>().set_offer(
|
||||
session
|
||||
.and_then(DevelopSession::profile_offer)
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
/// TRACES: FR-DEV-3e
|
||||
/// Saving the open DNG's embedded profile for every photograph from its
|
||||
/// body (D20). The photograph on screen already renders through it; the
|
||||
/// others pick it up when they are next decoded.
|
||||
fn wire_profile_offer(window: &AppWindow, session: &Rc<RefCell<Option<DevelopSession>>>) {
|
||||
let weak = window.as_weak();
|
||||
let session = session.clone();
|
||||
window.global::<ProfileOffer>().on_adopt(move || {
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
let mut guard = session.borrow_mut();
|
||||
let Some(s) = guard.as_mut() else { return };
|
||||
match s.adopt_profile() {
|
||||
Ok(path) => log::info!("camera profile saved to {}", path.display()),
|
||||
Err(e) => log::warn!("camera profile not saved: {e}"),
|
||||
}
|
||||
show_camera_profile(&w, Some(s));
|
||||
});
|
||||
}
|
||||
|
||||
fn wire_inference_status(window: &AppWindow) {
|
||||
let set = |w: &AppWindow| {
|
||||
let (line, detail) = inference::about_lines();
|
||||
@@ -2547,6 +2605,7 @@ fn build_show(
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
);
|
||||
show_camera_profile(window, l.session.as_ref());
|
||||
|
||||
// The panel is built from what the pipeline reports, so
|
||||
// this code names no operation (FR-DEV-3a).
|
||||
@@ -2604,6 +2663,7 @@ fn build_show(
|
||||
capture.set_exposure("".into());
|
||||
capture.set_dimensions("".into());
|
||||
capture.set_lens("".into());
|
||||
show_camera_profile(window, None);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -2691,6 +2751,8 @@ fn wire_remote_open(
|
||||
capture.set_camera("".into());
|
||||
capture.set_exposure("".into());
|
||||
capture.set_dimensions("".into());
|
||||
capture.set_lens("".into());
|
||||
show_camera_profile(&w, None);
|
||||
// The grid is one image at a time, so next/previous have nothing
|
||||
// to walk. Shown as 1 of 1 rather than left reading 0.
|
||||
w.set_index(0);
|
||||
@@ -2868,6 +2930,14 @@ fn wire_remote_open(
|
||||
capture.set_camera(describe_camera(&l.meta).into());
|
||||
capture.set_exposure(describe_exposure(&l.meta).into());
|
||||
capture.set_dimensions(format!("{} × {}", l.width, l.height).into());
|
||||
capture.set_lens(
|
||||
l.session
|
||||
.as_ref()
|
||||
.map(|s| s.lens_summary())
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
);
|
||||
show_camera_profile(&w, l.session.as_ref());
|
||||
match l.session {
|
||||
Some(mut s) => {
|
||||
w.global::<Develop>().set_enabled(true);
|
||||
|
||||
Reference in New Issue
Block a user