daniel-e / captcha

CAPTCHA library written in Rust.
MIT License
98 stars 18 forks source link

Can you support generating a captcha by specific text instead of random text? #20

Open omega-pw opened 1 year ago

omega-pw commented 1 year ago

I didn't find way to generate a captcha by specific text,can you add the support?

sergorl commented 1 year ago

Hi, guys, I support this question

sergorl commented 1 year ago

@omega4github , I found only this example of captcha generation from predefined symbols:


extern crate captcha;

use captcha::filters::{Cow, Noise, Wave};
use captcha::{Captcha, Geometry};

use std::path::Path;
fn main() {
    let mut c = Captcha::new();
    println!("{:?}", c.supported_chars());

    c.set_chars(&['0', '1', '2', '3', '4', '5', '6', '7', '8'])
        .add_chars(4)
        .apply_filter(Noise::new(0.2))
        .apply_filter(Wave::new(2.0, 20.0))
        .view(220, 120)
        .apply_filter(
            Cow::new()
                .min_radius(40)
                .max_radius(50)
                .circles(1)
                .area(Geometry::new(40, 150, 50, 70)),
        )
        .set_color([255, 128, 0]);
    c.save(Path::new("captcha.png")).expect("save failed");

    println!("{}", c.chars_as_string());
}
Maklestiguan commented 9 months ago

Try implementing something like this:


/// sets text of captcha
    pub fn set_text(&mut self, vec: &[char]) -> &mut Self {
        for char in vec {
            if let Some((c, i)) = self.random_char_as_image(Some(char)) { 
                let x = self.text_area.right;
                let y = (self.text_area.bottom + self.text_area.top) / 2 - i.height() / 2;
                self.img.add_image(x, y, &i);

                self.text_area.top = min(self.text_area.top, y);
                self.text_area.right = x + i.width() - 1;
                self.text_area.bottom = max(self.text_area.bottom, y + i.height() - 1);
                self.chars.push(c);
            }
        }

        self
    }

    // accept optional char
    fn random_char_as_image(&mut self, c: Option<&char>) -> Option<(char, Image)> {
        match c {
            Some(val) => match self.font.png(*val) {
                Some(p) => Image::from_png(p).map(|i| (*val, i)),
                None => None,
            },
            None =>  match self.use_font_chars.choose(&mut self.rng) {
                None => None,
                Some(c) => match self.font.png(*c) {
                    None => None,
                    Some(p) => Image::from_png(p).map(|i| (*c, i)),
                },
            }
        }
    }