Improve auto white balance#74
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughFreezes save context for async saves, records/restores metadata snapshots for edit saves and undos, adds a uint8 white-balance estimator and fast-path save with LUT caching, refactors uint8 save logic, tightens crop/rotation UI state, and adds tests for AWB, save fast-path, sidecar rebinding, and save-completion edge cases. Changes
Sequence DiagramsequenceDiagram
participant User
participant UI
participant App as AppController
participant Editor as ImageEditor
participant Sidecar as SidecarManager
User->>UI: trigger save
UI->>App: save_edited_image()
App->>App: freeze save context (metadata_path, save_sidecar, directory key)
App->>Editor: perform save (uint8 fast-path or general save)
Editor-->>App: return (saved_path, backup_path) or unexpected payload
App->>App: _on_save_finished(success, result, frozen_context)
alt result shaped as expected
App->>Sidecar: save_sidecar.update_metadata(metadata_path, edited=True, edited_date=...)
Sidecar-->>App: ack
App->>App: append undo record ("save_edit", {saved_path, backup_path, metadata_before, sidecar})
App->>UI: update status (saved)
else unexpected payload
App->>UI: update_status_message("Save callback malformed", timeout=5000)
end
User->>UI: trigger undo
UI->>App: undo_delete()
App->>App: pop undo record and parse payload
App->>Sidecar: sidecar.metadata_key_for_path(metadata_path) -> restore metadata snapshot
Sidecar-->>App: ack
App->>UI: update status (undo applied)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2edad69bbe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| self.undo_history.append( | ||
| ( | ||
| "save_edit", | ||
| self._build_edit_undo_data( | ||
| saved_path, |
There was a problem hiding this comment.
Skip cross-directory save undo entries
_on_save_finished unconditionally records a save_edit undo action even when the user has already switched to a different base folder. Because _switch_to_directory(..., update_base_directory=True) clears undo_history, this callback can repopulate the new folder’s undo stack with paths from the old folder; pressing Undo then restores/overwrites files outside the currently opened directory. Please only enqueue this undo entry when the save belongs to the active directory/session (or explicitly discard it after a base-folder switch).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
faststack/imaging/editor.py (1)
1496-1514: Consider removing redundantint()casts.
math.ceil()andmath.floor()already returnintin Python 3. The explicitint()casts on lines 1508 and 1510 are unnecessary.♻️ Suggested simplification
if method == "higher": - target_index = int(math.ceil(rank)) + target_index = math.ceil(rank) else: - target_index = int(math.floor(rank)) + target_index = math.floor(rank)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@faststack/imaging/editor.py` around lines 1496 - 1514, In _u8_percentile_from_hist, remove the redundant int() casts around math.ceil(rank) and math.floor(rank) when assigning target_index (they already return ints in Python 3); update the branches using method == "higher" / else to assign target_index = math.ceil(rank) and target_index = math.floor(rank) respectively, leaving the rest of the function (cdf, np.searchsorted, clamping) unchanged so type behavior remains correct.faststack/app.py (1)
8117-8120: Let preview completion own the AWB refresh.
_apply_preview_result()already emitscurrentImageSourceChangedand schedules the histogram once the new preview is ready. Doing both here first is extra work, and on slower renders it can briefly compute the histogram from the pre-AWB preview before the real one lands.Also applies to: 8180-8183
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@faststack/app.py` around lines 8117 - 8120, The code currently calls self.ui_state.currentImageSourceChanged.emit() and self.update_histogram() before kicking the preview worker, which duplicates work because _apply_preview_result() already emits currentImageSourceChanged and schedules the histogram when the real preview is ready; remove the preemptive calls to self.ui_state.currentImageSourceChanged.emit() and self.update_histogram() in the block containing self._kick_preview_worker() so that preview completion (_apply_preview_result) owns the AWB/preview refresh, and make the same removal in the analogous section around the other occurrence (the block referenced at lines ~8180-8183) to avoid computing histogram from the pre-AWB preview.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@faststack/app.py`:
- Around line 5895-5937: The helpers assume the image metadata key is the saved
file path; change the undo payload and parsing to carry an explicit main-image
metadata_path and use that when marking/restoring metadata: update
_build_edit_undo_data to include a metadata_path (string) in the returned dict,
update _parse_edit_undo_data to extract and return metadata_path (add it to the
returned tuple signature), and then modify callers to pass that metadata_path
into _mark_image_edited_in_sidecar (use metadata_path instead of saved_path) and
into the metadata restore routine (e.g., _restore_metadata_snapshot) so sidecar
updates/read use the original image identity rather than the physical
saved/backup path; keep legacy tuple handling backward-compatible by returning
None for metadata_path when the old tuple format is encountered.
---
Nitpick comments:
In `@faststack/app.py`:
- Around line 8117-8120: The code currently calls
self.ui_state.currentImageSourceChanged.emit() and self.update_histogram()
before kicking the preview worker, which duplicates work because
_apply_preview_result() already emits currentImageSourceChanged and schedules
the histogram when the real preview is ready; remove the preemptive calls to
self.ui_state.currentImageSourceChanged.emit() and self.update_histogram() in
the block containing self._kick_preview_worker() so that preview completion
(_apply_preview_result) owns the AWB/preview refresh, and make the same removal
in the analogous section around the other occurrence (the block referenced at
lines ~8180-8183) to avoid computing histogram from the pre-AWB preview.
In `@faststack/imaging/editor.py`:
- Around line 1496-1514: In _u8_percentile_from_hist, remove the redundant int()
casts around math.ceil(rank) and math.floor(rank) when assigning target_index
(they already return ints in Python 3); update the branches using method ==
"higher" / else to assign target_index = math.ceil(rank) and target_index =
math.floor(rank) respectively, leaving the rest of the function (cdf,
np.searchsorted, clamping) unchanged so type behavior remains correct.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1935eb0b-dfb2-40d6-b321-5eb4ddf65765
📒 Files selected for processing (6)
faststack/app.pyfaststack/imaging/editor.pyfaststack/qml/Components.qmlfaststack/tests/test_auto_white_balance.pyfaststack/tests/test_editor_lifecycle_and_safety.pyfaststack/tests/test_editor_reopening.py
…a way that matches the actual workflow: the saved file can be a developed or restored variant, while the metadata belongs to the owning image entry.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
faststack/app.py (1)
5980-6000:⚠️ Potential issue | 🟠 MajorUndo is still restoring the whole metadata record.
This helper replaces or deletes the entire
EntryMetadataentry, even though these edit flows only mutateeditedandedited_date. If the user togglesfavorite,uploaded,todo, etc. after the save, undoing the edit will silently wipe those newer changes. Restore only the fields this action owns, and only drop the entry when it did not exist before and the remaining metadata is all-default.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@faststack/app.py`:
- Around line 8001-8004: The fast-path AWB save uses the main image filepath
when calling image_editor.load_image(cached_preview=..., preview_only=True)
causing developed-variant saves to overwrite the main image; update the load to
mirror execute_crop() by resolving the currently viewed variant (use
_get_save_target_path_for_current_view or the variant path when
view_override_kind == "developed") and call get_decoded_image/current variant
path so image_editor.load_image loads the viewed variant as the source instead
of the main filepath, ensuring saves write to the correct developed variant.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7a08e694-05a1-4422-bece-c01cf3e2de8b
📒 Files selected for processing (3)
faststack/app.pyfaststack/imaging/editor.pyfaststack/tests/test_editor_reopening.py
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
faststack/app.py (1)
5520-5524: Avoid broad exception catch in undo restore flow.Catching all exceptions here can mask programming errors and make undo failures harder to diagnose.
🧭 Narrow exception scope
- except Exception as e: + except (OSError, RuntimeError, ValueError) as e: self.update_status_message(f"Undo failed: {e}") if Path(backup_path).exists(): self.undo_history.append((action_type, action_data, timestamp))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@faststack/app.py` around lines 5520 - 5524, The current undo restore block is using a broad "except Exception as e" which can hide programming bugs; change it to catch only expected recovery errors (e.g., FileNotFoundError, OSError, shutil.Error or specific I/O/restore errors thrown by the restore logic) around the restore attempt, call self.update_status_message(f"Undo failed: {e}") and append to self.undo_history only when the backup exists, and re-raise or let unexpected exceptions propagate (or log them with full trace) so that programming errors in the undo flow are not silently swallowed; locate the try/except around the restore logic that references backup_path, self.update_status_message, self.undo_history, action_type, action_data, and timestamp to apply this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@faststack/app.py`:
- Around line 1983-1984: The tuple guard allows tuples longer than 2 and then
raises ValueError when unpacking; change the check to require exactly two
elements (e.g., replace "isinstance(result, tuple) and len(result) >= 2" with
"isinstance(result, tuple) and len(result) == 2") or explicitly extract the
first two values (saved_path, backup_path = result[0], result[1]) so you never
attempt a 2-variable unpack on a longer tuple and the malformed-result handling
remains reachable.
- Around line 8255-8259: The AWB diagnostics logging currently indexes
diagnostics keys directly and can raise KeyError; in the logging call that
formats estimate values (used after estimate_auto_white_balance()), replace
direct indexing of "selected_pixels", "stride", and "neutrality_limit" with safe
lookups (e.g., estimate.get("selected_pixels", 0), estimate.get("stride", 0),
estimate.get("neutrality_limit", 0.0)) or compute fallback values before
formatting so the log statement always has valid values; locate the code around
the AWB logging block and the estimate_auto_white_balance() usage to apply these
.get() lookups or precomputed defaults.
---
Nitpick comments:
In `@faststack/app.py`:
- Around line 5520-5524: The current undo restore block is using a broad "except
Exception as e" which can hide programming bugs; change it to catch only
expected recovery errors (e.g., FileNotFoundError, OSError, shutil.Error or
specific I/O/restore errors thrown by the restore logic) around the restore
attempt, call self.update_status_message(f"Undo failed: {e}") and append to
self.undo_history only when the backup exists, and re-raise or let unexpected
exceptions propagate (or log them with full trace) so that programming errors in
the undo flow are not silently swallowed; locate the try/except around the
restore logic that references backup_path, self.update_status_message,
self.undo_history, action_type, action_data, and timestamp to apply this change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f5f2635f-4d81-4210-91fb-d0f7a629d752
📒 Files selected for processing (2)
faststack/app.pyfaststack/tests/test_editor_reopening.py
🚧 Files skipped from review as they are similar to previous changes (1)
- faststack/tests/test_editor_reopening.py
Summary by CodeRabbit
New Features
Bug Fixes
Tests