forgewright 0.2.0

Standalone UI automation — CDP for browsers, UIA for Windows desktop apps
Documentation
pub struct BinaryImage {
    pub width: u32,
    pub height: u32,
    pub data: Vec<bool>,
}

pub fn detect_edges(gray: &[u8], width: u32, height: u32, threshold: f32) -> BinaryImage {
    let w = width as i32;
    let h = height as i32;
    let get = |x: i32, y: i32| -> f32 {
        if x < 0 || y < 0 || x >= w || y >= h { return 0.0; }
        gray[(y * w + x) as usize] as f32
    };

    let mut data = vec![false; (width * height) as usize];
    for y in 1..h - 1 {
        for x in 1..w - 1 {
            let gx = -get(x-1,y-1) - 2.0*get(x-1,y) - get(x-1,y+1)
                    + get(x+1,y-1) + 2.0*get(x+1,y) + get(x+1,y+1);
            let gy = -get(x-1,y-1) - 2.0*get(x,y-1) - get(x+1,y-1)
                    + get(x-1,y+1) + 2.0*get(x,y+1) + get(x+1,y+1);
            let mag = (gx * gx + gy * gy).sqrt();
            data[(y * w + x) as usize] = mag > threshold;
        }
    }
    BinaryImage { width, height, data }
}

pub fn detect_edges_from_file(path: &str, threshold: f32) -> Result<BinaryImage, String> {
    let img = image::open(path).map_err(|e| format!("{}", e))?;
    let gray = img.to_luma8();
    Ok(detect_edges(gray.as_raw(), gray.width(), gray.height(), threshold))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn circle_edges() {
        let (w, h) = (64u32, 64u32);
        let mut gray = vec![0u8; (w * h) as usize];
        for y in 0..h { for x in 0..w {
            let dx = x as f32 - 32.0;
            let dy = y as f32 - 32.0;
            if dx * dx + dy * dy < 20.0 * 20.0 { gray[(y * w + x) as usize] = 255; }
        }}
        let edges = detect_edges(&gray, w, h, 100.0);
        let edge_count = edges.data.iter().filter(|&&v| v).count();
        assert!(edge_count > 20);
    }
}