mod flags;
mod opacity;
pub use flags::Flags;
use image::{imageops, DynamicImage, ImageBuffer, Rgba};
use imageproc::{
drawing::{draw_filled_circle, draw_filled_rect},
rect::Rect,
};
pub use opacity::Opacity;
use std::ops::Div;
type Image = ImageBuffer<Rgba<u8>, Vec<u8>>;
fn draw<T>(
image: &DynamicImage,
flag: &[(u8, u8, u8)],
opacity: Option<Opacity>,
flag_transform: Option<Box<T>>,
) -> Image
where
T: Sized + Fn(Image, u32, u32) -> Image,
{
let mut image = image.to_rgba8();
let (width, height) = image.dimensions();
let mut flag_image = ImageBuffer::<Rgba<u8>, Vec<u8>>::new(width, height);
let segment_count = flag.len();
let segment_size = (height as f32).div(segment_count as f32).ceil() as u32;
let a = opacity.unwrap_or(Opacity(127)).0;
for (i, (r, g, b)) in flag.iter().enumerate() {
let i = i as u32;
let rect = Rect::at(0, (i * segment_size) as i32).of_size(width, segment_size);
let colour = Rgba([*r, *g, *b, a]);
flag_image = draw_filled_rect(&flag_image, rect, colour);
}
if let Some(transform) = flag_transform {
flag_image = transform(flag_image, width, height);
}
imageops::overlay(&mut image, &flag_image, 0, 0);
image.clone()
}
pub fn overlay<T>(image: &DynamicImage, flag: T, opacity: Option<Opacity>) -> Image
where
T: Into<Vec<(u8, u8, u8)>>,
{
draw::<fn(Image, u32, u32) -> Image>(image, &flag.into(), opacity, None)
}
pub fn circle<T>(image: &DynamicImage, flag: T, thickness: Option<u8>) -> Image
where
T: Into<Vec<(u8, u8, u8)>>,
{
draw(
image,
&flag.into(),
Some(Opacity(255)),
Some(Box::new(move |img, width, height| {
draw_filled_circle(
&img,
((width / 2) as i32, (height / 2) as i32),
(width / 2
- if let Some(mut thickness) = thickness {
if thickness > 10 {
thickness = 10;
}
thickness * 8
} else {
24
} as u32) as i32,
Rgba([0, 0, 0, 0]),
)
})),
)
}