#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub enum CaptureFormat {
Png,
Jpeg,
Bmp,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct ScreenCaptureConfig {
pub width: u32,
pub height: u32,
pub format: CaptureFormat,
pub include_alpha: bool,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CaptureBuffer {
pub pixels: Vec<u8>,
pub width: u32,
pub height: u32,
pub channels: u32,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CaptureResult {
pub buffer: CaptureBuffer,
pub format: CaptureFormat,
pub byte_size: usize,
}
#[allow(dead_code)]
pub fn default_screen_capture_config(w: u32, h: u32) -> ScreenCaptureConfig {
ScreenCaptureConfig {
width: w,
height: h,
format: CaptureFormat::Png,
include_alpha: false,
}
}
#[allow(dead_code)]
pub fn new_capture_buffer(w: u32, h: u32, channels: u32) -> CaptureBuffer {
let size = w as usize * h as usize * channels as usize;
CaptureBuffer {
pixels: vec![0u8; size],
width: w,
height: h,
channels,
}
}
#[allow(dead_code)]
pub fn capture_stub(cfg: &ScreenCaptureConfig) -> CaptureResult {
let channels = if cfg.include_alpha { 4 } else { 3 };
let buffer = new_capture_buffer(cfg.width, cfg.height, channels);
let byte_size = buffer.pixels.len();
CaptureResult {
buffer,
format: cfg.format.clone(),
byte_size,
}
}
#[allow(dead_code)]
pub fn capture_pixel(buf: &CaptureBuffer, x: u32, y: u32) -> &[u8] {
let ch = buf.channels as usize;
let idx = (y as usize * buf.width as usize + x as usize) * ch;
&buf.pixels[idx..idx + ch]
}
#[allow(dead_code)]
pub fn capture_format_name(fmt: &CaptureFormat) -> &'static str {
match fmt {
CaptureFormat::Png => "png",
CaptureFormat::Jpeg => "jpeg",
CaptureFormat::Bmp => "bmp",
}
}
#[allow(dead_code)]
pub fn capture_result_to_json(r: &CaptureResult) -> String {
format!(
r#"{{"format":"{}","width":{},"height":{},"channels":{},"byte_size":{}}}"#,
capture_format_name(&r.format),
r.buffer.width,
r.buffer.height,
r.buffer.channels,
r.byte_size,
)
}
#[allow(dead_code)]
pub fn capture_buffer_to_grayscale(buf: &CaptureBuffer) -> CaptureBuffer {
let pixel_count = buf.width as usize * buf.height as usize;
let ch = buf.channels as usize;
let mut gray = vec![0u8; pixel_count];
for (i, g) in gray.iter_mut().enumerate() {
let base = i * ch;
*g = if ch >= 3 {
let r = buf.pixels[base] as f32;
let gv = buf.pixels[base + 1] as f32;
let b = buf.pixels[base + 2] as f32;
(0.299 * r + 0.587 * gv + 0.114 * b) as u8
} else if ch == 1 {
buf.pixels.get(base).copied().unwrap_or(0)
} else {
0
};
}
CaptureBuffer {
pixels: gray,
width: buf.width,
height: buf.height,
channels: 1,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_config_fields() {
let cfg = default_screen_capture_config(1920, 1080);
assert_eq!(cfg.width, 1920);
assert_eq!(cfg.height, 1080);
assert_eq!(cfg.format, CaptureFormat::Png);
assert!(!cfg.include_alpha);
}
#[test]
fn new_capture_buffer_size() {
let buf = new_capture_buffer(10, 10, 3);
assert_eq!(buf.pixels.len(), 300);
assert!(buf.pixels.iter().all(|&b| b == 0));
}
#[test]
fn capture_stub_rgb() {
let cfg = default_screen_capture_config(4, 4);
let r = capture_stub(&cfg);
assert_eq!(r.buffer.channels, 3);
assert_eq!(r.byte_size, 4 * 4 * 3);
}
#[test]
fn capture_stub_rgba() {
let cfg = ScreenCaptureConfig {
width: 2,
height: 2,
format: CaptureFormat::Png,
include_alpha: true,
};
let r = capture_stub(&cfg);
assert_eq!(r.buffer.channels, 4);
assert_eq!(r.byte_size, 16);
}
#[test]
fn capture_pixel_returns_correct_slice() {
let mut buf = new_capture_buffer(4, 4, 3);
buf.pixels[3] = 10;
buf.pixels[4] = 20;
buf.pixels[5] = 30;
let px = capture_pixel(&buf, 1, 0);
assert_eq!(px, &[10, 20, 30]);
}
#[test]
fn capture_format_names() {
assert_eq!(capture_format_name(&CaptureFormat::Png), "png");
assert_eq!(capture_format_name(&CaptureFormat::Jpeg), "jpeg");
assert_eq!(capture_format_name(&CaptureFormat::Bmp), "bmp");
}
#[test]
fn result_to_json_contains_fields() {
let cfg = default_screen_capture_config(64, 64);
let r = capture_stub(&cfg);
let json = capture_result_to_json(&r);
assert!(json.contains("png"));
assert!(json.contains("64"));
assert!(json.contains("byte_size"));
}
#[test]
fn grayscale_conversion_dimensions() {
let buf = new_capture_buffer(8, 8, 3);
let gray = capture_buffer_to_grayscale(&buf);
assert_eq!(gray.channels, 1);
assert_eq!(gray.width, 8);
assert_eq!(gray.height, 8);
assert_eq!(gray.pixels.len(), 64);
}
#[test]
fn grayscale_luminance_correct() {
let mut buf = new_capture_buffer(1, 1, 3);
buf.pixels[0] = 255;
buf.pixels[1] = 0;
buf.pixels[2] = 0;
let gray = capture_buffer_to_grayscale(&buf);
assert!((gray.pixels[0] as i32 - 76).abs() <= 1);
}
#[test]
fn grayscale_single_channel_passthrough() {
let mut buf = new_capture_buffer(2, 2, 1);
buf.pixels[0] = 200;
let gray = capture_buffer_to_grayscale(&buf);
assert_eq!(gray.pixels[0], 200);
}
}