From cbdce347f07518c9ce2eb16576f55243cffef9fb Mon Sep 17 00:00:00 2001 From: David Mann Date: Sun, 8 Nov 2026 15:12:49 +0100 Subject: [PATCH] Background Eraser: Protect Foreground keeps the per-channel distance; tolerance doc Only the sample match uses the measured increase-plus-decrease distance (#11901). Protect Foreground Color keeps today's largest per-channel difference, as #11903 asks for its unmeasured cases. The tolerance doc describes the new distance and the graded falloff. Co-Authored-By: Claude Opus 5.5 --- crates/paint/src/bg_erase.rs | 14 ++++++++++++-- crates/paint/src/bg_erase_graded_alpha_tests.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/paint/src/bg_erase.rs b/crates/paint/src/bg_erase.rs index 751d58519b..a47c5acbfb 100644 --- a/crates/paint/src/bg_erase.rs +++ b/crates/paint/src/bg_erase.rs @@ -17,7 +17,11 @@ use crate::retouch::{Footprint, Region, alpha_index, apply_dab_stroke}; pub struct BgEraseSettings { pub sampling: Sampling, pub limits: Limits, - /// 0..1: largest per-channel difference from the sampled colour that is erased. + /// 0..1: how far from the sampled colour a colour is still partly erased. The distance is the + /// largest increase plus the largest decrease over the colour channels (`dist`); an exact + /// match is erased fully, then less the further a colour is, and colours at or beyond the + /// Tolerance are kept (`graded_weight`). Protect Foreground Color still compares the + /// foreground by the largest per-channel difference (`max_channel_dist`). pub tolerance: f32, /// Keep pixels that match the foreground colour. pub protect_foreground: bool, @@ -52,6 +56,12 @@ fn dist(a: &[f32], b: &[f32]) -> f32 { up + down } +/// The largest per-channel difference of `a` from `b`: the distance Protect Foreground Color keeps +/// using (#11901 measured only the sample match; #11903 keeps today's measure for the foreground). +fn max_channel_dist(a: &[f32], b: &[f32]) -> f32 { + a.iter().zip(b).fold(0.0f32, |m, (x, y)| m.max((x - y).abs())) +} + /// The match weight of one dab for a colour `d` away from the sampled colour (#11901): an exact /// match is erased fully, then the weight falls off linearly over the whole Tolerance `tol` after /// a short plateau `d0 = min(tol / 20, 8 levels)`, and colours at or beyond the Tolerance are kept. @@ -151,7 +161,7 @@ pub fn background_eraser_effect(pre: &Surface, bs: &BgEraseSettings) -> Option