Open a photograph with the edit it already carries, when DarkRoom has none
The library's DNGs carry the photographer's earlier develop settings in their embedded XMP — the house style their photographs were made with. A photograph opened with no edit of DarkRoom's now starts from that earlier edit, translated (HSL bands, highlights, blacks and the rest), as one undoable step named "Earlier Edit"; from there it is an ordinary edit, saved with the photograph. Export does the same, so a photograph never opened exports as opening it would show. Only on positive evidence that there is no DarkRoom edit: a local file with no sidecar beside it, or a server that answered "no such file" with nothing in the cache. The stored-edit fetch now says which (FetchedSidecar::absent). Offline, unreachable or unreadable never counts — the earlier edit would otherwise be saved over a real edit that merely failed to arrive.
This commit is contained in:
@@ -76,6 +76,11 @@ pub struct DevelopSession {
|
||||
/// the info panel offers to save for every photograph from that camera
|
||||
/// (D20). `None` once taken up.
|
||||
pub(super) profile_offer: Option<Arc<dr_decode::dcp::Dcp>>,
|
||||
/// TRACES: FR-DEV-6
|
||||
/// The edit the file already carries from the photographer's earlier work, translated, waiting for the
|
||||
/// word that this photograph has no edit of DarkRoom's own
|
||||
/// ([`Self::adopt_earlier_edit`]).
|
||||
pub(super) earlier_edit: Option<Preset>,
|
||||
/// Kept so the session can build GPU resources after construction.
|
||||
///
|
||||
/// The distance fields behind a subject mask are made when a layer is
|
||||
@@ -439,6 +444,7 @@ impl DevelopSession {
|
||||
// and not found" — `lens_summary` distinguishes them.
|
||||
lens_profile_found: false,
|
||||
profile_offer: None,
|
||||
earlier_edit: None,
|
||||
ctx: ctx.clone(),
|
||||
graph,
|
||||
history,
|
||||
@@ -610,6 +616,33 @@ impl DevelopSession {
|
||||
.map(Arc::new);
|
||||
}
|
||||
|
||||
/// TRACES: FR-DEV-6
|
||||
/// Remember the earlier edit stored in the file this session opened.
|
||||
pub fn set_earlier_edit(&mut self, edit: Option<Preset>) {
|
||||
self.earlier_edit = edit;
|
||||
}
|
||||
|
||||
/// TRACES: FR-DEV-6
|
||||
/// Apply the file's earlier edit, as the photograph's starting point, so it
|
||||
/// keeps the style it was given before it came to DarkRoom.
|
||||
///
|
||||
/// Only for a photograph DarkRoom has no edit of: the caller says so, and
|
||||
/// must know it rather than guess — a stored edit that could not be
|
||||
/// fetched is not an absent one, and the earlier edit would then be
|
||||
/// saved over it on the way out. One undoable step, so undo shows the
|
||||
/// photograph without it; from there it is an ordinary edit, saved with
|
||||
/// the photograph. Taken, so a second call does nothing.
|
||||
pub fn adopt_earlier_edit(&mut self) -> bool {
|
||||
let Some(edit) = self.earlier_edit.take() else {
|
||||
return false;
|
||||
};
|
||||
let rebake = edit.apply(&mut self.graph, Scope::adjustments());
|
||||
self.pay_film_debt(&rebake);
|
||||
self.history
|
||||
.record(&self.graph, Edit::Action(labels::step::EARLIER_EDIT));
|
||||
true
|
||||
}
|
||||
|
||||
/// TRACES: FR-DEV-3e
|
||||
/// What to tell the photographer about the camera profile (D20).
|
||||
///
|
||||
@@ -888,6 +921,34 @@ mod tests {
|
||||
assert_eq!(jpeg.profile_summary(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_earlier_edit_is_adopted_once_and_can_be_undone() {
|
||||
// TRACES: FR-DEV-6
|
||||
let Some(ctx) = headless() else { return };
|
||||
let mut s = DevelopSession::open(&ctx, &raw_with(None), dr_types::Orientation::NORMAL)
|
||||
.expect("session");
|
||||
assert!(!s.adopt_earlier_edit(), "nothing to adopt yet");
|
||||
|
||||
let earlier = dr_preset_xmp::read_xmp(
|
||||
r#"<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/" crs:SaturationAdjustmentBlue="+58" crs:Highlights2012="-40"/></rdf:RDF></x:xmpmeta>"#,
|
||||
)
|
||||
.expect("an edit")
|
||||
.preset;
|
||||
s.set_earlier_edit(Some(earlier));
|
||||
assert!(s.adopt_earlier_edit());
|
||||
let blue = || {
|
||||
s.graph.param(
|
||||
dr_pipeline::ops::colour_mixer::ID,
|
||||
dr_pipeline::ParamId("blue_sat"),
|
||||
)
|
||||
};
|
||||
assert_eq!(blue(), Some(58.0));
|
||||
assert!(!s.adopt_earlier_edit(), "taken: a second call does nothing");
|
||||
assert!(!s.graph.is_neutral());
|
||||
s.undo();
|
||||
assert!(s.graph.is_neutral(), "undo shows the photograph without it");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_a_copyable_profile_is_offered() {
|
||||
// TRACES: FR-DEV-3e
|
||||
|
||||
Reference in New Issue
Block a user