Skip to content

Commit

Permalink
Merge pull request #20 from hlsxx/fix-formats
Browse files Browse the repository at this point in the history
cargo fmt + extendtab
  • Loading branch information
samirdjelal authored Jan 10, 2025
2 parents e8e68ad + 5d08e79 commit ba0a29a
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 243 deletions.
2 changes: 1 addition & 1 deletion src/captcha/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mod standard;

pub use standard::*;
pub use standard::*;
192 changes: 101 additions & 91 deletions src/captcha/standard.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
use std::io::Cursor;
use base64::Engine;
use base64::engine::general_purpose;
use image::{ImageBuffer, Rgb};
use base64::Engine;
use image::DynamicImage;
use image::ImageOutputFormat::Jpeg;
use image::{ImageBuffer, Rgb};
use imageproc::drawing::{draw_cubic_bezier_curve_mut, draw_hollow_ellipse_mut, draw_text_mut};
use rand::{Rng, thread_rng};
use rand::{thread_rng, Rng};
use rusttype::{Font, Scale};
use std::io::Cursor;

// Define the verification code characters.
// Remove 0, O, I, L and other easily confusing letters
pub const BASIC_CHAR: [char; 54] = [
'2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M',
'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M',
'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
];

// Define a random color for a string
pub const LIGHT_BASIC_COLOR: [[u8; 3]; 5] = [
[214, 14, 50],
[240, 181, 41],
[176, 203, 40],
[105, 137, 194],
[242, 140, 71],
[214, 14, 50],
[240, 181, 41],
[176, 203, 40],
[105, 137, 194],
[242, 140, 71],
];

pub const DARK_BASIC_COLOR: [[u8; 3]; 5] = [
[251, 188, 5],
[116, 192, 255],
[255, 224, 133],
[198, 215, 97],
[247, 185, 168],
[251, 188, 5],
[116, 192, 255],
[255, 224, 133],
[198, 215, 97],
[247, 185, 168],
];

// Define background color
Expand All @@ -46,32 +47,32 @@ pub const SCALE_LG: Scale = Scale { x: 53.0, y: 50.0 };
* params num - maximum random number
*/
pub fn get_rnd(num: usize) -> usize {
let mut rng = thread_rng();
rng.gen_range(0..=num)
let mut rng = thread_rng();
rng.gen_range(0..=num)
}

/**
* Generate an array of captcha characters
* params num - The number of digits of the verification code and the maximum cannot exceed 53
*/
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
let mut res = vec![];
for _ in 0..num {
let rnd = get_rnd(53);
res.push(BASIC_CHAR[rnd].to_string())
}
res
}

/**
* Get color
*/
pub fn get_color(dark_mode: bool) -> Rgb<u8> {
let rnd = get_rnd(4);
if dark_mode {
return Rgb(DARK_BASIC_COLOR[rnd]);
}
Rgb(LIGHT_BASIC_COLOR[rnd])
let rnd = get_rnd(4);
if dark_mode {
return Rgb(DARK_BASIC_COLOR[rnd]);
}
Rgb(LIGHT_BASIC_COLOR[rnd])
}

/**
Expand All @@ -81,27 +82,27 @@ pub fn get_color(dark_mode: bool) -> Rgb<u8> {
* return: random number
*/
pub fn get_next(min: f32, max: u32) -> f32 {
min + get_rnd(max as usize - min as usize) as f32
min + get_rnd(max as usize - min as usize) as f32
}

/**
* Get font
*/
pub fn get_font() -> Font<'static> {
let font = Vec::from(include_bytes!("../../fonts/arial.ttf") as &[u8]);
Font::try_from_vec(font).unwrap()
let font = Vec::from(include_bytes!("../../fonts/arial.ttf") as &[u8]);
Font::try_from_vec(font).unwrap()
}

/**
* Get an image with a white background
*/
pub fn get_image(width: u32, height: u32, dark_mode: bool) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
ImageBuffer::from_fn(width, height, |_, _| {
if dark_mode {
return image::Rgb(DARK);
}
image::Rgb(LIGHT)
})
ImageBuffer::from_fn(width, height, |_, _| {
if dark_mode {
return image::Rgb(DARK);
}
image::Rgb(LIGHT)
})
}

/**
Expand All @@ -110,53 +111,62 @@ pub fn get_image(width: u32, height: u32, dark_mode: bool) -> ImageBuffer<Rgb<u8
* image - Background picture
*/
pub fn cyclic_write_character(
res: &[String],
image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
dark_mode: bool,
res: &[String],
image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
dark_mode: bool,
) {
let c = (image.width() - 10) / res.len() as u32;
let y = image.height() / 2 - 15;

let scale = match res.len() {
1..=3 => SCALE_LG,
4..=5 => SCALE_MD,
_ => SCALE_SM,
};

for (i, _) in res.iter().enumerate() {
let text = &res[i];

draw_text_mut(image, get_color(dark_mode), 5 + (i as u32 * c) as i32, y as i32, scale, &get_font(), text);
}
let c = (image.width() - 10) / res.len() as u32;
let y = image.height() / 2 - 15;

let scale = match res.len() {
1..=3 => SCALE_LG,
4..=5 => SCALE_MD,
_ => SCALE_SM,
};

for (i, _) in res.iter().enumerate() {
let text = &res[i];

draw_text_mut(
image,
get_color(dark_mode),
5 + (i as u32 * c) as i32,
y as i32,
scale,
&get_font(),
text,
);
}
}

/**
* Draw interference lines
* params image - Background picture
*/
pub fn draw_interference_line(image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>, dark_mode: bool) {
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);
// Randomly draw bezier curves
draw_cubic_bezier_curve_mut(
image,
(x1, y1),
(x2, y2),
(ctrl_x, ctrl_y),
(ctrl_x2, ctrl_y2),
get_color(dark_mode),
);
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);

// Randomly draw bezier curves
draw_cubic_bezier_curve_mut(
image,
(x1, y1),
(x2, y2),
(ctrl_x, ctrl_y),
(ctrl_x2, ctrl_y2),
get_color(dark_mode),
);
}

/**
Expand All @@ -165,25 +175,25 @@ pub fn draw_interference_line(image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>, dark_mo
* image - Background picture
*/
pub fn draw_interference_ellipse(
num: usize,
image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
dark_mode: bool,
num: usize,
image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
dark_mode: bool,
) {
for _ in 0..num {
let w = (10 + 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(dark_mode));
}
for _ in 0..num {
let w = (10 + 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(dark_mode));
}
}

/**
* Convert image to JPEG base64 string
* parma image - Image
*/
pub fn to_base64_str(image: &DynamicImage, compression: u8) -> String {
let mut buf = Cursor::new(Vec::new());
image.write_to(&mut buf, Jpeg(compression)).unwrap();
let res_base64 = general_purpose::STANDARD.encode(buf.into_inner());
format!("data:image/jpeg;base64,{}", res_base64)
let mut buf = Cursor::new(Vec::new());
image.write_to(&mut buf, Jpeg(compression)).unwrap();
let res_base64 = general_purpose::STANDARD.encode(buf.into_inner());
format!("data:image/jpeg;base64,{}", res_base64)
}
Loading

0 comments on commit ba0a29a

Please sign in to comment.