Skip to content

feat(color): area sampling and colour preview for the white balance picker - #1832

Merged
CyberTimon merged 5 commits into
CyberTimon:mainfrom
lalibertemarc:feature/wb-picker-sample-area
Oct 5, 2026
Merged

CyberTimon merged 5 commits into
CyberTimon:mainfrom
lalibertemarc:feature/wb-picker-sample-area

Conversation

@lalibertemarc

@lalibertemarc lalibertemarc commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Description

Makes the white balance picker sample an area instead of a few pixels, and shows a colour preview while hovering.

Closes #1251 and potentially #1768. Partially addresses #747: it adds the colour preview under the cursor, but not the magnifier loupe.

Clicking the same spot often gave very different results (#1251). The old picker averaged an 11×11 patch of the medium thumbnail JPEG, which caused that in several ways:

  • The thumbnail is 8-bit and tone-mapped.
  • It can be out of date after a crop.
  • Any saved white balance is already baked into it.
  • The click position ignored rotation and flips.

Sampling now runs in Rust on the original image, the same linear data the shader's white balance step works on.

How it works now

  • Hover: a square outline follows the cursor. It is always 16 screen pixels, so it covers fewer image pixels as you zoom in, which is how the zoom-coupled idea in FEATURE: White Balance Picker Sampling Area. #1251 suggested it.
  • Click: averages the pixels inside that square.
  • Click and drag: draws a rectangle and averages everything inside it on release. This is the rectangle idea from FEATURE: White Balance Picker Sampling Area. #1251. A drag needs at least 4 screen pixels of movement, so a slightly shaky click still counts as a click.
  • Swatch: a small box next to the cursor shows the averaged colour, its RGB values and the Temperature/Tint a pick would set, in the active white balance mode (Kelvin or relative). It updates live while dragging.
  • The picker stays active after a pick, as before. No keybinds changed.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Performance improvement
  • Code refactoring
  • Documentation update
  • UI/UX improvement
  • Build/CI or Dependency update

Changes Made

  • src-tauri/src/image_processing.rs: new sample_white_balance command.
    • Takes the four corners of the selection as UV coordinates in the original image. After rotation or perspective, a screen rectangle maps to a rotated quad in the original, so the command averages the pixels inside that quad, not its bounding box.
    • Reads the f32 buffer directly, so raw values above 1.0 aren't clipped. Non-raw images are converted from sRGB to linear per pixel, matching the shader.
    • Large selections are thinned to about 262k samples so they stay fast.
    • The averaged linear RGB goes through the existing white_balance::pick_white_balance from feat(color): Kelvin white balance mode and physically based white balance #1830, with the image's as-shot white balance as the current one, because the original image is rendered at as-shot. It returns an absolute Kelvin/tint.
    • Runs on spawn_blocking, because it is called while hovering.
    • apply_srgb_to_linear now reuses the same srgb_channel_to_linear helper rather than keeping its own copy of the curve.
    • Adds 5 unit tests: neutral grey gives the as-shot white balance, sRGB linearisation, colour cast direction, the sub-pixel fallback, and a rotated quad excluding corner pixels.
  • src-tauri/src/white_balance.rs: pick_white_balance is no longer called from the frontend, so it is a plain function instead of a Tauri command.
  • src-tauri/src/lib.rs: registers sample_white_balance and drops the pick_white_balance command.
  • src/components/panel/editor/ImageCanvas.tsx
    • Removes the thumbnail-based handleWbClick.
    • A pick is written in the active white balance mode, the same way the old handler did: Kelvin mode sets the absolute value, relative mode converts it to an offset from as-shot.
    • The selection is mapped to the original image through crop, rotation, flips, 90° orientation steps and perspective, using the existing mapScreenToUv.
    • Hover requests are throttled: one in flight at a time, newest wins. Results are dropped if the image changes or the picker is turned off mid-request.
    • The hover square and drag box are drawn in the Konva overlay (WbSampleOutline).
    • The swatch is an HTML element scaled against the zoom, so it stays the same size on screen. It flips to the other side of the cursor near the right and bottom edges.
  • src/components/ui/AppProperties.tsx: adds Invokes.SampleWhiteBalance and removes the now unused Invokes.PickWhiteBalance.

No new translation keys. The swatch reuses the existing Temperature/Tint labels.

Screenshots/Videos

Temperature is displayed in Kelvin when Kelvin mode is on

image image

drag and drop for bigger detect zone :
image

Testing

  • These changes were tested locally by a human and confirmed to work.
  • I haven't added any automated tests to the code because the codebase currently lacks a test suite.

Test Configuration:

  • OS: Windows 10 Home (19045)
  • Hardware: AMD Ryzen 5 3600X, NVIDIA GeForce RTX 2070

All checks below were compared against upstream/main (48aac8a):

  • tsc: 70 errors, the same as upstream, none in the changed files.
  • ESLint: ImageCanvas.tsx has 72 problems against 73 on upstream (one any removed); AppProperties.tsx is unchanged.
  • i18n:check, check-runtime.mjs and i18n:lint: same output as upstream.
  • cargo clippy --all-targets: 0 warnings.
  • rustfmt: clean.
  • cargo test: the 5 new tests pass.

Checklist

  • My code follows the project's code style
  • I haven't added unnecessary AI-generated code comments
  • My changes generate no new warnings or errors

Additional Notes

Known approximations. The sample is read from the original image before any edits, at the as-shot white balance, which is what the absolute Kelvin/tint pick needs. This means:

  • Mask-based white balance and AI patches are ignored.
  • Lens distortion correction isn't included in the position mapping, the same as the guided perspective tool, so the sampled spot can be slightly off near the image edges.
  • Exposure and vignetting don't change channel ratios, so they don't matter.

Rebased on #1830 (Kelvin white balance mode). Now that #1830 is merged, this branch is rebased onto main. The last commit connects the area sampler to #1830's pick_white_balance, so picks give the same Kelvin/tint model as the rest of the white balance panel.

AI Disclaimer:

Please state the involvement of AI in this PR:

  • This PR is created by an AI agent
  • This PR is mostly AI-generated but edited/merged together by a human
  • This PR was handwritten with AI assistance (spell check, logic suggestions, error resolving)
  • This PR contains only blood, sweat, and coffee (AI-free)

🤖 Generated with Claude Code

@lalibertemarc
lalibertemarc force-pushed the feature/wb-picker-sample-area branch from b82c2c0 to 3c5d279 Compare October 4, 2026 12:58
lalibertemarc and others added 4 commits October 4, 2026 16:20
Click averages a square under the cursor, click-drag averages a
rectangle. Sampling moves to a new sample_white_balance Tauri command
that reads the linear original image and maps the selection through
rotation, flip, orientation, crop and perspective, instead of reading
the stale medium thumbnail JPEG.

While hovering, a swatch shows the averaged colour, its RGB values and
the resulting temperature/tint.

Refs CyberTimon#1251, CyberTimon#747

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reuse srgb_channel_to_linear in apply_srgb_to_linear instead of keeping
a second copy of the curve, and draw the hover square and drag box with
one WbSampleOutline component.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The area sampler now turns its averaged linear RGB into an absolute
white balance with white_balance::pick_white_balance, using the loaded
image's as-shot white balance, since the original image is rendered at
as-shot. The pick is written in the active white balance mode (Kelvin or
relative), and the hover swatch shows the values in that mode too.

pick_white_balance is no longer called from the frontend, so it is a
plain function again and the pick_white_balance command and invoke are
removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lalibertemarc
lalibertemarc force-pushed the feature/wb-picker-sample-area branch from 3c5d279 to e4d6fd1 Compare October 4, 2026 20:25
lalibertemarc added a commit to lalibertemarc/RapidRAW that referenced this pull request Oct 4, 2026
Brings in the rebased CyberTimon#1832: swatch label fix, shared sRGB decode and
sample outline, and the mode-aware swatch readout. Conflicts kept the
branch's picker code and personal's Color Mixer pipette and auto
straighten entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Araoo

Araoo commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

I tested this PR locally and everything works as intended. Sampling in Rust from the original as-shot data makes the picker much more reliable: repeated clicks on the same spot now give consistent results. @lalibertemarc Thanks for this work!

@CyberTimon

Copy link
Copy Markdown
Owner

LGTM, thanks a lot!!

@CyberTimon
CyberTimon merged commit 55be822 into CyberTimon:main Oct 5, 2026
4 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FEATURE: White Balance Picker Sampling Area.

3 participants