1mod flags;
2mod opacity;
3
4pub use flags::Flags;
5use image::{imageops, DynamicImage, ImageBuffer, Rgba};
6use imageproc::{
7 drawing::{draw_filled_circle, draw_filled_rect},
8 rect::Rect,
9};
10pub use opacity::Opacity;
11use std::ops::Div;
12
13type Image = ImageBuffer<Rgba<u8>, Vec<u8>>;
14
15fn draw<T>(
16 image: &DynamicImage,
17 flag: &[(u8, u8, u8)],
18 opacity: Option<Opacity>,
19 flag_transform: Option<Box<T>>,
20) -> Image
21where
22 T: Sized + Fn(Image, u32, u32) -> Image,
23{
24 let mut image = image.to_rgba8();
26 let (width, height) = image.dimensions();
27
28 let mut flag_image = ImageBuffer::<Rgba<u8>, Vec<u8>>::new(width, height);
30 let segment_count = flag.len();
31 let segment_size = (height as f32).div(segment_count as f32).ceil() as u32;
32 let a = opacity.unwrap_or(Opacity(127)).0;
33
34 for (i, (r, g, b)) in flag.iter().enumerate() {
35 let i = i as u32;
36 let rect = Rect::at(0, (i * segment_size) as i32).of_size(width, segment_size);
37 let colour = Rgba([*r, *g, *b, a]);
38
39 flag_image = draw_filled_rect(&flag_image, rect, colour);
40 }
41
42 if let Some(transform) = flag_transform {
44 flag_image = transform(flag_image, width, height);
45 }
46
47 imageops::overlay(&mut image, &flag_image, 0, 0);
49
50 image.clone()
51}
52
53pub fn overlay<T>(image: &DynamicImage, flag: T, opacity: Option<Opacity>) -> Image
55where
56 T: Into<Vec<(u8, u8, u8)>>,
57{
58 draw::<fn(Image, u32, u32) -> Image>(image, &flag.into(), opacity, None)
59}
60
61pub fn circle<T>(image: &DynamicImage, flag: T, thickness: Option<u8>) -> Image
63where
64 T: Into<Vec<(u8, u8, u8)>>,
65{
66 draw(
67 image,
68 &flag.into(),
69 Some(Opacity(255)),
70 Some(Box::new(move |img, width, height| {
71 draw_filled_circle(
72 &img,
73 ((width / 2) as i32, (height / 2) as i32),
74 (width / 2
75 - if let Some(mut thickness) = thickness {
76 if thickness > 10 {
77 thickness = 10;
78 }
79
80 thickness * 8
81 } else {
82 24
83 } as u32) as i32,
84 Rgba([0, 0, 0, 0]),
85 )
86 })),
87 )
88}