use crate::geometry::{Point, Size};
#[derive(Debug, PartialEq)]
pub enum PixelSource {
Image,
Blend(f32),
Background,
}
impl PixelSource {
pub fn at(
pixel: Point,
img_position: &Point,
img_size: &Size,
corner_radius: &Option<u32>,
) -> Self {
if is_border_pixel(&pixel, img_position, img_size) {
return PixelSource::Background;
} else if corner_radius.is_none() {
return PixelSource::Image;
}
let radius = corner_radius.unwrap() as i32;
let x = (pixel.x() - img_position.x()) as i32;
let y = (pixel.y() - img_position.y()) as i32;
let width = img_size.width() as i32;
let height = img_size.height() as i32;
let (dx, dy) = if x < radius && y < radius {
(radius - x, radius - y)
} else if x < radius && y >= height - radius {
(radius - x, y - height + radius + 1)
} else if x >= width - radius && y < radius {
(x - width + radius + 1, radius - y)
} else if x >= width - radius && y >= height - radius {
(x - width + radius + 1, y - height + radius + 1)
} else {
return PixelSource::Image;
};
let distance_squared = dx * dx + dy * dy;
let radius_squared = radius * radius;
if distance_squared > radius_squared {
PixelSource::Background
} else if distance_squared <= radius_squared - radius {
PixelSource::Image
} else {
let distance = (distance_squared as f32).sqrt();
let blend = 1.0 - (distance / radius as f32);
PixelSource::Blend(blend)
}
}
}
fn is_border_pixel(pixel: &Point, img_position: &Point, img_size: &Size) -> bool {
if pixel.x() < img_position.x() || pixel.x() >= img_position.x() + img_size.width() {
return true;
}
if pixel.y() < img_position.y() || pixel.y() >= img_position.y() + img_size.height() {
return true;
}
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn image_pixels() {
let img_position = Point::new(10, 10);
let img_size = Size::new(100, 100);
let corner_radius = Some(10);
let mid_image_pixel = Point::new(60, 60);
assert_eq!(
PixelSource::at(mid_image_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Image
);
let top_left_in_corner_radius_pixel = Point::new(15, 15);
assert_eq!(
PixelSource::at(
top_left_in_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Image
);
let top_right_in_corner_radius_pixel = Point::new(105, 15);
assert_eq!(
PixelSource::at(
top_right_in_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Image
);
let bottom_left_in_corner_radius_pixel = Point::new(15, 105);
assert_eq!(
PixelSource::at(
bottom_left_in_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Image
);
let bottom_right_in_corner_radius_pixel = Point::new(105, 105);
assert_eq!(
PixelSource::at(
bottom_right_in_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Image
);
let corner_radius = None;
let top_left_pixel = Point::new(10, 10);
assert_eq!(
PixelSource::at(top_left_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Image
);
let top_right_pixel = Point::new(109, 10);
assert_eq!(
PixelSource::at(top_right_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Image
);
let bottom_left_pixel = Point::new(10, 109);
assert_eq!(
PixelSource::at(bottom_left_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Image
);
let bottom_right_pixel = Point::new(109, 109);
assert_eq!(
PixelSource::at(bottom_right_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Image
);
}
#[test]
fn border_pixels() {
let img_position = Point::new(10, 10);
let img_size = Size::new(100, 100);
let corner_radius = Some(10);
let left_border_pixel = Point::new(5, 60);
assert_eq!(
PixelSource::at(left_border_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Background
);
let right_border_pixel = Point::new(115, 60);
assert_eq!(
PixelSource::at(right_border_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Background
);
let top_border_pixel = Point::new(60, 5);
assert_eq!(
PixelSource::at(top_border_pixel, &img_position, &img_size, &corner_radius),
PixelSource::Background
);
let bottom_border_pixel = Point::new(60, 115);
assert_eq!(
PixelSource::at(
bottom_border_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let top_left_corner_pixel = Point::new(5, 5);
assert_eq!(
PixelSource::at(
top_left_corner_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let top_right_corner_pixel = Point::new(115, 5);
assert_eq!(
PixelSource::at(
top_right_corner_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let bottom_left_corner_pixel = Point::new(5, 115);
assert_eq!(
PixelSource::at(
bottom_left_corner_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let bottom_right_corner_pixel = Point::new(115, 115);
assert_eq!(
PixelSource::at(
bottom_right_corner_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let top_left_outside_corner_radius_pixel = Point::new(12, 12);
assert_eq!(
PixelSource::at(
top_left_outside_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let top_right_outside_corner_radius_pixel = Point::new(108, 12);
assert_eq!(
PixelSource::at(
top_right_outside_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let bottom_left_outside_corner_radius_pixel = Point::new(12, 108);
assert_eq!(
PixelSource::at(
bottom_left_outside_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
let bottom_right_outside_corner_radius_pixel = Point::new(108, 108);
assert_eq!(
PixelSource::at(
bottom_right_outside_corner_radius_pixel,
&img_position,
&img_size,
&corner_radius
),
PixelSource::Background
);
}
#[test]
fn blended_pixels() {
let img_position = Point::new(10, 10);
let img_size = Size::new(100, 100);
let corner_radius = Some(10);
let top_left_corner_pixel = Point::new(13, 13);
let pixel_source = PixelSource::at(
top_left_corner_pixel,
&img_position,
&img_size,
&corner_radius,
);
match pixel_source {
PixelSource::Blend(blend) => {
assert!(blend > 0.01);
assert!(blend < 0.02);
}
_ => panic!("Expected PixelSource::Blend"),
}
let top_right_corner_pixel = Point::new(106, 13);
let pixel_source = PixelSource::at(
top_right_corner_pixel,
&img_position,
&img_size,
&corner_radius,
);
match pixel_source {
PixelSource::Blend(blend) => {
assert!(blend > 0.01);
assert!(blend < 0.02);
}
_ => panic!("Expected PixelSource::Blend"),
}
let bottom_left_corner_pixel = Point::new(13, 106);
let pixel_source = PixelSource::at(
bottom_left_corner_pixel,
&img_position,
&img_size,
&corner_radius,
);
match pixel_source {
PixelSource::Blend(blend) => {
assert!(blend > 0.01);
assert!(blend < 0.02);
}
_ => panic!("Expected PixelSource::Blend"),
}
let bottom_right_corner_pixel = Point::new(106, 106);
let pixel_source = PixelSource::at(
bottom_right_corner_pixel,
&img_position,
&img_size,
&corner_radius,
);
match pixel_source {
PixelSource::Blend(blend) => {
assert!(blend > 0.01);
assert!(blend < 0.02);
}
_ => panic!("Expected PixelSource::Blend"),
}
}
}