| pub fn dilate(bitmap: &[u8], width: usize, height: usize, radius: u8) -> Vec<u8> { |
| if radius == 0 || bitmap.is_empty() { return bitmap.to_vec(); } |
| let r = radius as isize; |
| let mut out = vec![0u8; width * height]; |
| for y in 0..height { |
| for x in 0..width { |
| let mut max_val = bitmap[y * width + x]; |
| for dy in -r..=r { |
| for dx in -r..=r { |
| let ny = (y as isize + dy).clamp(0, height as isize - 1) as usize; |
| let nx = (x as isize + dx).clamp(0, width as isize - 1) as usize; |
| max_val = max_val.max(bitmap[ny * width + nx]); |
| } |
| } |
| out[y * width + x] = max_val; |
| } |
| } |
| out |
| } |
|
|
| pub fn thicken_light(bitmap: &[u8], width: usize, height: usize, strength: f32) -> Vec<u8> { |
| if strength <= 0.0 || bitmap.is_empty() { return bitmap.to_vec(); } |
| let mut out = bitmap.to_vec(); |
| let threshold = 64u8; |
| let strength_byte = (strength * 255.0).clamp(0.0, 255.0) as u8; |
| for y in 0..height { |
| for x in 0..width { |
| let idx = y * width + x; |
| if bitmap[idx] >= threshold { continue; } |
| let mut neighbor_max = 0u8; |
| for dy in -1..=1isize { |
| for dx in -1..=1isize { |
| if dy == 0 && dx == 0 { continue; } |
| let ny = (y as isize + dy).clamp(0, height as isize - 1) as usize; |
| let nx = (x as isize + dx).clamp(0, width as isize - 1) as usize; |
| neighbor_max = neighbor_max.max(bitmap[ny * width + nx]); |
| } |
| } |
| if neighbor_max > threshold { |
| out[idx] = out[idx].saturating_add(strength_byte); |
| } |
| } |
| } |
| out |
| } |
|
|
| pub fn r8_to_rgb(r8: &[u8]) -> Vec<u8> { |
| let mut rgb = Vec::with_capacity(r8.len() * 3); |
| for &v in r8 { rgb.push(v); rgb.push(v); rgb.push(v); } |
| rgb |
| } |
|
|
| pub fn r8_to_rgba(r8: &[u8]) -> Vec<u8> { |
| let mut rgba = Vec::with_capacity(r8.len() * 4); |
| for &v in r8 { rgba.push(v); rgba.push(v); rgba.push(v); rgba.push(v); } |
| rgba |
| } |
|
|