commit 6b6c01b8f28addd3df211bd714628529d3f701d2
parent 8fb69816832f5d1bbdc82078c0e9aad40d6e9763
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Thu, 30 Mar 2023 01:19:28 -0700
cleanup
Diffstat:
| M | src/lechatphp/mod.rs | | | 88 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
1 file changed, 49 insertions(+), 39 deletions(-)
diff --git a/src/lechatphp/mod.rs b/src/lechatphp/mod.rs
@@ -179,6 +179,12 @@ impl Letter {
#[derive(Debug)]
struct CaptchaErr(String);
+impl From<&str> for CaptchaErr {
+ fn from(value: &str) -> Self {
+ CaptchaErr(value.to_owned())
+ }
+}
+
impl Display for CaptchaErr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
@@ -194,13 +200,52 @@ impl std::error::Error for CaptchaErr {}
// Red circle is 17x17 (initial point)
fn solve_difficulty3(img: &DynamicImage) -> Result<String, CaptchaErr> {
//img.save(format!("captcha.gif")).unwrap();
+
+ // Step1: Find all letters with red on the center
+ let letters_map = find_letters(&img);
+
+ if letters_map.len() != 5 {
+ return Err(CaptchaErr(format!("did not find exactly 5 letters {}", letters_map.len())));
+ }
+
+ // Step2: Find the starting letter
+ let starting = get_starting_letter(&img, &letters_map).ok_or(CaptchaErr("could not find starting letter".to_owned()))?;
+
+ let mut answer = String::new();
+ let mut visited = HashSet::<Letter>::new();
+ let mut letter = starting;
+ answer.push(letter.character);
+ visited.insert(letter.clone());
+ for i in 0..4 {
+ let top_left = Point::new(letter.offset.x-5, letter.offset.y-3);
+ let mut rect = Rect{p1: top_left, width: 8+5+6, height: 14+3+2};
+ let mut retry = 0;
+ 'retry_loop: loop {
+ retry += 1;
+ let square = img.crop_imm(rect.p1.x, rect.p1.y, rect.width, rect.height);
+ let red_px_pts = get_contour_red_pixels(&rect.p1, &square);
+ let nb_lines = if i == 0 { 1 } else { 2 };
+ if red_px_pts.len() != nb_lines {
+ if retry < 10 {
+ rect.enlarge();
+ continue 'retry_loop;
+ }
+ return Err(CaptchaErr(format!("letter #{} {:?} invalid nb lines detected", i+1, letter)));
+ }
+ letter = get_next_node(&red_px_pts, &letter, &letters_map, &visited, i, nb_lines)?;
+ break 'retry_loop;
+ }
+ answer.push(letter.character);
+ visited.insert(letter.clone());
+ }
+ Ok(answer)
+}
+
+fn find_letters(img: &DynamicImage) -> HashMap<char, Letter> {
let image_width = 150;
let image_height = 200;
let min_px_for_letter = 21;
-
let mut letters_map: HashMap<char, Letter> = HashMap::new();
-
- // Step1: Find all letters with red on the center
for y in 0..image_height {
for x in 0..image_width {
let letter_img = img.crop_imm(x, y, 8, 14);
@@ -243,42 +288,7 @@ fn solve_difficulty3(img: &DynamicImage) -> Result<String, CaptchaErr> {
}
}
}
-
- if letters_map.len() != 5 {
- return Err(CaptchaErr(format!("did not find exactly 5 letters {}", letters_map.len())));
- }
-
- // Step2: Find the starting letter
- let starting = get_starting_letter(&img, &letters_map).ok_or(CaptchaErr("could not find starting letter".to_owned()))?;
-
- let mut answer = String::new();
- let mut visited = HashSet::<Letter>::new();
- let mut letter = starting;
- answer.push(letter.character);
- visited.insert(letter.clone());
- for i in 0..4 {
- let top_left = Point::new(letter.offset.x-5, letter.offset.y-3);
- let mut rect = Rect{p1: top_left, width: 8+5+6, height: 14+3+2};
- let mut retry = 0;
- 'retry_loop: loop {
- retry += 1;
- let square = img.crop_imm(rect.p1.x, rect.p1.y, rect.width, rect.height);
- let red_px_pts = get_contour_red_pixels(&rect.p1, &square);
- let nb_lines = if i == 0 { 1 } else { 2 };
- if red_px_pts.len() != nb_lines {
- if retry < 10 {
- rect.enlarge();
- continue 'retry_loop;
- }
- return Err(CaptchaErr(format!("letter #{} {:?} invalid nb lines detected", i+1, letter)));
- }
- letter = get_next_node(&red_px_pts, &letter, &letters_map, &visited, i, nb_lines)?;
- break 'retry_loop;
- }
- answer.push(letter.character);
- visited.insert(letter.clone());
- }
- Ok(answer)
+ letters_map
}
fn get_starting_letter(img: &DynamicImage, letters_map: &HashMap<char, Letter>) -> Option<Letter> {