feat(iced): implement selection menu operations
- Add Inverse selection (Shift+Ctrl+I) with engine.invert_selection() - Add Shrink, Feather, Border, Smooth menu items with parameter dialogs - Implement selection_border() and selection_smooth() in engine API - Implement border_mask() and smooth_mask() in hcie-selection crate - Update SelectionOpApply handler for all selection operations
This commit is contained in:
@@ -282,4 +282,87 @@ pub fn lasso_fill_mask(mask: &mut [u8], w: u32, h: u32, points: &[(u32, u32)]) {
|
||||
k += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a border from a selection mask by keeping only edge pixels.
|
||||
///
|
||||
/// **Purpose:** Extracts the outline/border of a selection by keeping pixels
|
||||
/// that are selected but have at least one unselected neighbor.
|
||||
///
|
||||
/// **Arguments:**
|
||||
/// - `mask`: The selection mask to process (modified in place).
|
||||
/// - `w`, `h`: Canvas dimensions.
|
||||
/// - `thickness`: Border thickness in pixels.
|
||||
pub fn border_mask(mask: &mut [u8], w: u32, h: u32, thickness: u32) {
|
||||
if thickness == 0 { return; }
|
||||
let original = mask.to_vec();
|
||||
|
||||
// First, create the outer border by eroding
|
||||
let mut eroded = original.clone();
|
||||
for _ in 0..thickness {
|
||||
let old = eroded.clone();
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let i = (y * w + x) as usize;
|
||||
if old[i] == 0 { continue; }
|
||||
let neighbors = [
|
||||
(x.wrapping_sub(1), y), (x + 1, y),
|
||||
(x, y.wrapping_sub(1)), (x, y + 1),
|
||||
];
|
||||
let mut has_zero = false;
|
||||
for (nx, ny) in neighbors {
|
||||
if nx >= w || ny >= h || old[(ny * w + nx) as usize] == 0 {
|
||||
has_zero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if has_zero {
|
||||
eroded[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Border = original - eroded (pixels in original but not in eroded)
|
||||
for i in 0..mask.len() {
|
||||
if original[i] > 0 && eroded[i] == 0 {
|
||||
mask[i] = original[i];
|
||||
} else {
|
||||
mask[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Smooth a selection mask using a box blur.
|
||||
///
|
||||
/// **Purpose:** Softens jagged edges of a selection by applying a box blur
|
||||
/// within the specified radius, creating smoother transitions.
|
||||
///
|
||||
/// **Arguments:**
|
||||
/// - `mask`: The selection mask to process (modified in place).
|
||||
/// - `w`, `h`: Canvas dimensions.
|
||||
/// - `radius`: Blur radius in pixels.
|
||||
pub fn smooth_mask(mask: &mut [u8], w: u32, h: u32, radius: u32) {
|
||||
if radius == 0 { return; }
|
||||
let r = radius as i32;
|
||||
let size = (w * h) as usize;
|
||||
let mut result = vec![0u8; size];
|
||||
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let mut sum = 0u32;
|
||||
let mut count = 0u32;
|
||||
for dy in -r..=r {
|
||||
for dx in -r..=r {
|
||||
let nx = (x as i32 + dx).clamp(0, w as i32 - 1) as u32;
|
||||
let ny = (y as i32 + dy).clamp(0, h as i32 - 1) as u32;
|
||||
sum += mask[(ny * w + nx) as usize] as u32;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
result[(y * w + x) as usize] = (sum / count) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
mask.copy_from_slice(&result);
|
||||
}
|
||||
Reference in New Issue
Block a user