Skip to content

Commit b7f6c05

Browse files
committed
Snapshots should always be applied from a source image to a target
This prevents snapshots from being applied in an unloaded image, which causes loss of image history if undo is not applied. This tends to happen and go unnoticed with duplicates.
1 parent fb095bd commit b7f6c05

4 files changed

Lines changed: 36 additions & 27 deletions

File tree

‎RELEASE_NOTES.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ changes (where available).
137137
- Fixed auto-applied denoise presets running a second time on images
138138
produced by AI raw denoise.
139139

140+
- Fixed snapshots being applied onto the original image instead of the
141+
current image.
142+
140143
## Lua
141144

142145
### API Version

‎src/common/history_snapshot.c‎

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,20 @@ void dt_history_snapshot_undo_create(const dt_imgid_t imgid,
154154
dt_unlock_image(imgid);
155155
}
156156

157-
static void _history_snapshot_restore(const dt_imgid_t imgid,
157+
static void _history_snapshot_restore(const dt_imgid_t source_imgid,
158+
const dt_imgid_t dest_imgid,
158159
const int snap_id,
159160
const int history_end)
160161
{
161-
// restore the given snapshot for imgid
162+
// restore the given snapshot from source to target
162163
sqlite3_stmt *stmt;
163164
gboolean all_ok = TRUE;
164165

165-
dt_lock_image(imgid);
166+
dt_lock_image(dest_imgid);
166167

167168
dt_database_start_transaction(darktable.db);
168169

169-
dt_history_delete_on_image_ext(imgid, FALSE, FALSE);
170+
dt_history_delete_on_image_ext(dest_imgid, FALSE, FALSE);
170171
DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_TAG_CHANGED);
171172

172173
// if no history end it means the image history was discarded,
@@ -181,14 +182,15 @@ static void _history_snapshot_restore(const dt_imgid_t imgid,
181182
// clang-format off
182183
DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
183184
"INSERT INTO main.history"
184-
" SELECT imgid, num, module, operation, op_params, enabled, "
185+
" SELECT ?1, num, module, operation, op_params, enabled, "
185186
" blendop_params, blendop_version, multi_priority,"
186187
" multi_name, multi_name_hand_edited "
187188
" FROM memory.snapshot_history"
188-
" WHERE imgid=?2 AND id=?1", -1, &stmt, NULL);
189+
" WHERE imgid=?2 AND id=?3", -1, &stmt, NULL);
189190
// clang-format on
190-
DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
191-
DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
191+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid);
192+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, source_imgid);
193+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, snap_id);
192194
all_ok &= (sqlite3_step(stmt) == SQLITE_DONE);
193195
sqlite3_finalize(stmt);
194196

@@ -197,14 +199,15 @@ static void _history_snapshot_restore(const dt_imgid_t imgid,
197199
// clang-format off
198200
DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
199201
"INSERT INTO main.masks_history"
200-
" SELECT imgid, num, formid, form, name, version,"
202+
" SELECT ?1, num, formid, form, name, version,"
201203
" points, points_count, source"
202204
" FROM memory.snapshot_masks_history"
203-
" WHERE imgid=?2 AND id=?1",
205+
" WHERE imgid=?2 AND id=?3",
204206
-1, &stmt, NULL);
205207
// clang-format on
206-
DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
207-
DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
208+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid);
209+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, source_imgid);
210+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, snap_id);
208211
all_ok &= (sqlite3_step(stmt) == SQLITE_DONE);
209212
sqlite3_finalize(stmt);
210213

@@ -213,20 +216,21 @@ static void _history_snapshot_restore(const dt_imgid_t imgid,
213216
// clang-format off
214217
DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
215218
"INSERT INTO main.module_order"
216-
" SELECT imgid, version, iop_list"
219+
" SELECT ?1, version, iop_list"
217220
" FROM memory.snapshot_module_order"
218-
" WHERE imgid=?2 AND id=?1", -1, &stmt, NULL);
221+
" WHERE imgid=?2 AND id=?3", -1, &stmt, NULL);
219222
// clang-format on
220-
DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
221-
DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
223+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid);
224+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, source_imgid);
225+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, snap_id);
222226
all_ok &= (sqlite3_step(stmt) == SQLITE_DONE);
223227

224228
sqlite3_finalize(stmt);
225229

226230
end_restore:
227231

228232
// set history end
229-
all_ok &= dt_image_set_history_end(imgid, history_end);
233+
all_ok &= dt_image_set_history_end(dest_imgid, history_end);
230234

231235
if(all_ok)
232236
dt_database_release_transaction(darktable.db);
@@ -235,19 +239,20 @@ static void _history_snapshot_restore(const dt_imgid_t imgid,
235239
dt_database_rollback_transaction(darktable.db);
236240
dt_print(DT_DEBUG_ALWAYS,
237241
"[_history_snapshot_undo_restore] fails to restore a snapshot for %d",
238-
imgid);
242+
dest_imgid);
239243
}
240-
dt_unlock_image(imgid);
244+
dt_unlock_image(dest_imgid);
241245

242-
dt_history_hash_write_from_history(imgid, DT_HISTORY_HASH_CURRENT);
246+
dt_history_hash_write_from_history(dest_imgid, DT_HISTORY_HASH_CURRENT);
243247
}
244248

245-
void dt_history_snapshot_restore(const dt_imgid_t imgid,
249+
void dt_history_snapshot_restore(const dt_imgid_t source_imgid,
250+
const dt_imgid_t dest_imgid,
246251
const int snap_id,
247252
const int history_end)
248253
{
249254
if(history_end != -1)
250-
_history_snapshot_restore(imgid, snap_id, history_end);
255+
_history_snapshot_restore(source_imgid, dest_imgid, snap_id, history_end);
251256
}
252257

253258
void dt_history_snapshot_clear(const dt_imgid_t imgid,
@@ -309,11 +314,11 @@ void dt_history_snapshot_undo_pop(gpointer user_data,
309314

310315
if(action == DT_ACTION_UNDO)
311316
{
312-
_history_snapshot_restore(hist->imgid, hist->before, hist->before_history_end);
317+
_history_snapshot_restore(hist->imgid, hist->imgid, hist->before, hist->before_history_end);
313318
}
314319
else
315320
{
316-
_history_snapshot_restore(hist->imgid, hist->after, hist->after_history_end);
321+
_history_snapshot_restore(hist->imgid, hist->imgid, hist->after, hist->after_history_end);
317322
}
318323

319324
*imgs = g_list_append(*imgs, GINT_TO_POINTER(hist->imgid));

‎src/common/history_snapshot.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ void dt_history_snapshot_undo_lt_history_data_free(gpointer data);
5151
void dt_history_snapshot_create(const dt_imgid_t imgid,
5252
const int snap_id,
5353
const int history_end);
54-
void dt_history_snapshot_restore(const dt_imgid_t imgid,
54+
void dt_history_snapshot_restore(const dt_imgid_t source_imgid,
55+
const dt_imgid_t dest_imgid,
5556
const int snap_id,
5657
const int history_end);
5758
void dt_history_snapshot_clear(const dt_imgid_t imgid,

‎src/libs/snapshots.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,9 +1034,9 @@ static void _lib_snapshots_restore_callback(GtkButton *widget,
10341034

10351035
dt_lib_snapshot_t *s = &d->snapshot[restore_idx];
10361036

1037-
const dt_imgid_t imgid = s->imgid;
1037+
const dt_imgid_t imgid = darktable.develop->image_storage.id;
10381038

1039-
dt_history_snapshot_restore(imgid, s->id, s->history_end);
1039+
dt_history_snapshot_restore(s->imgid, imgid, s->id, s->history_end);
10401040

10411041
dt_dev_undo_start_record(darktable.develop);
10421042

0 commit comments

Comments
 (0)