use std::ops::{Deref, DerefMut};
pub use captcha::{
CaptchaName, Difficulty,
filters::{Dots, Noise, Wave},
};
pub const BASE64_PNG_HEAD: &str = "data:image/png;base64,";
pub struct Captcha(captcha::Captcha);
impl Default for Captcha {
fn default() -> Self {
Self::new()
}
}
impl Captcha {
pub fn new() -> Self {
Self(captcha::Captcha::new())
}
pub fn by_name(d: Difficulty, t: CaptchaName) -> Self {
Self(captcha::by_name(d, t))
}
pub fn as_base64(&self) -> Option<(String, String)> {
let chars = self.0.chars_as_string();
let png_base64 = self.0.as_base64()?;
Some((chars, format!("{BASE64_PNG_HEAD}{png_base64}")))
}
pub fn as_png(&self) -> Option<(String, Vec<u8>)> {
let chars = self.0.chars_as_string();
let png_bytes = self.0.as_png()?;
Some((chars, png_bytes))
}
pub fn as_wav(&self) -> (String, Vec<Option<Vec<u8>>>) {
let chars = self.0.chars_as_string();
let wav = self.0.as_wav();
(chars, wav)
}
}
impl Deref for Captcha {
type Target = captcha::Captcha;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Captcha {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use super::*;
#[test]
fn captcha_amelia_easy() {
let captcha = Captcha::by_name(Difficulty::Easy, CaptchaName::Amelia);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_amelia_easy.png"))
.unwrap();
}
#[test]
fn captcha_amelia_medium() {
let captcha = Captcha::by_name(Difficulty::Medium, CaptchaName::Amelia);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_amelia_medium.png"))
.unwrap();
}
#[test]
fn captcha_amelia_hard() {
let captcha = Captcha::by_name(Difficulty::Hard, CaptchaName::Amelia);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_amelia_hard.png"))
.unwrap();
}
#[test]
fn captcha_lucy_easy() {
let captcha = Captcha::by_name(Difficulty::Easy, CaptchaName::Lucy);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_lucy_easy.png"))
.unwrap();
}
#[test]
fn captcha_lucy_medium() {
let captcha = Captcha::by_name(Difficulty::Medium, CaptchaName::Lucy);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_lucy_medium.png"))
.unwrap();
}
#[test]
fn captcha_lucy_hard() {
let captcha = Captcha::by_name(Difficulty::Hard, CaptchaName::Lucy);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_lucy_hard.png"))
.unwrap();
}
#[test]
fn captcha_mila_easy() {
let captcha = Captcha::by_name(Difficulty::Easy, CaptchaName::Mila);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_mila_easy.png"))
.unwrap();
}
#[test]
fn captcha_mila_medium() {
let captcha = Captcha::by_name(Difficulty::Medium, CaptchaName::Mila);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_mila_medium.png"))
.unwrap();
}
#[test]
fn captcha_mila_hard() {
let captcha = Captcha::by_name(Difficulty::Hard, CaptchaName::Mila);
let chars = captcha.chars_as_string();
println!("chars={chars}");
captcha
.save(Path::new("src/fnd/captcha/doc/captcha_mila_hard.png"))
.unwrap();
}
#[test]
fn captcha_flexible() {
let mut captcha = Captcha::new();
captcha
.add_chars(5)
.apply_filter(Noise::new(0.4))
.apply_filter(Wave::new(2.0, 20.0).horizontal())
.apply_filter(Wave::new(2.0, 20.0).vertical())
.view(220, 120)
.apply_filter(Dots::new(15));
let (chars, base64) = captcha.as_base64().unwrap();
println!("chars={chars}\n{base64}");
}
}