use image::{ImageBuffer, Rgb};
use imageproc::drawing::{draw_cubic_bezier_curve_mut, draw_hollow_ellipse_mut, draw_text_mut};
use rand::{thread_rng, Rng};
use rusttype::Font;
use crate::basic_data::{BASIC_CHAR, BASIC_COLOR, SCALE, WHITE};
use image::ImageOutputFormat::Png;
use image::DynamicImage;
fn get_rnd(num: usize) -> usize {
let mut rng = thread_rng();
rng.gen_range(0..=num)
}
pub fn get_captcha(num: usize) -> Vec<String> {
let mut res = vec![];
for _ in 0..num {
let rnd = get_rnd(53);
res.push(BASIC_CHAR[rnd].to_string())
}
res
}
fn get_color() -> Rgb<u8> {
let rnd = get_rnd(4);
Rgb(BASIC_COLOR[rnd])
}
fn get_next(min: f32, max: u32) -> f32 {
min + get_rnd(max as usize - min as usize) as f32
}
fn get_font() -> Font<'static> {
let font = Vec::from(include_bytes!("../font/arial.ttf") as &[u8]);
Font::try_from_vec(font).unwrap()
}
fn get_image(width: u32, height: u32) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
ImageBuffer::from_fn(width, height, |_, _| {
image::Rgb(WHITE)
})
}
fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>) {
let c = (image.width() - 10) / res.len() as u32;
let y = image.height() / 2 - 15;
for (i, _) in res.iter().enumerate() {
let text = &res[i];
draw_text_mut(image, get_color(), 5 + (i as u32 * c), y, SCALE, &get_font(), text);
}
}
fn draw_interference_line(image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>) {
let width = image.width();
let height = image.height();
let x1: f32 = 5.0;
let y1 = get_next(x1, height / 2);
let x2 = (width - 5) as f32;
let y2 = get_next((height / 2) as f32, height - 5);
let ctrl_x = get_next((width / 4) as f32, width / 4 * 3);
let ctrl_y = get_next(x1, height - 5);
let ctrl_x2 = get_next((width / 4) as f32, width / 4 * 3);
let ctrl_y2 = get_next(x1, height - 5);
draw_cubic_bezier_curve_mut(image, (x1, y1), (x2, y2), (ctrl_x, ctrl_y), (ctrl_x2, ctrl_y2), get_color());
}
fn draw_interference_ellipse(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>) {
for _ in 0..num {
let w = (2 + get_rnd(5)) as i32;
let x = get_rnd((image.width() - 25) as usize) as i32;
let y = get_rnd((image.height() - 15) as usize) as i32;
draw_hollow_ellipse_mut(image, (x, y), w, w, get_color());
}
}
fn to_base64_str(image: ImageBuffer<Rgb<u8>, Vec<u8>>) -> String {
let base_img = DynamicImage::ImageRgb8(image);
let mut buf = vec![];
base_img.write_to(&mut buf, Png).unwrap();
let res_base64 = base64::encode(&buf);
format!("data:image/png;base64,{}", res_base64)
}
pub fn get_captcha_img(res: Vec<String>, width: u32, height: u32) -> String {
let mut image = get_image(width, height);
cyclic_write_character(&res, &mut image);
draw_interference_line(&mut image);
draw_interference_ellipse(2, &mut image);
to_base64_str(image)
}