use super::image_utils::{bgra_to_rgba, remove_row_padding};
use super::Screen;
use core_graphics::display::{
kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay,
};
use core_graphics::geometry::{CGPoint, CGRect, CGSize};
use image::RgbaImage;
pub fn all() -> Result<Vec<Screen>, String> {
let ids = CGDisplay::active_online_displays();
let mut out = Vec::with_capacity(ids.len());
for id in ids {
let display = CGDisplay::new(id);
let bounds = display.bounds();
let (pw, ph) = pixel_dimensions(&display);
let scale = if bounds.size.width > 0.0 {
(pw as f64 / bounds.size.width) as f32
} else {
1.0
};
out.push(Screen {
id,
x: bounds.origin.x as i32,
y: bounds.origin.y as i32,
width: bounds.size.width as u32,
height: bounds.size.height as u32,
scale_factor: scale.max(1.0),
});
}
Ok(out)
}
fn pixel_dimensions(display: &CGDisplay) -> (usize, usize) {
if let Some(mode) = display.display_mode() {
return (mode.pixel_width() as usize, mode.pixel_height() as usize);
}
let b = display.bounds().size;
(b.width as usize, b.height as usize)
}
fn capture_rect(screen: &Screen, rect: CGRect) -> Result<RgbaImage, String> {
let cg_image = CGDisplay::screenshot(
rect,
kCGWindowListOptionOnScreenOnly,
kCGNullWindowID,
kCGWindowImageDefault,
)
.ok_or_else(|| format!("CGDisplay::screenshot failed for display {}", screen.id))?;
let width = cg_image.width();
let height = cg_image.height();
let cleaned = remove_row_padding(
width,
height,
cg_image.bytes_per_row(),
Vec::from(cg_image.data().bytes()),
);
bgra_to_rgba(width as u32, height as u32, cleaned)
}
pub fn capture(screen: &Screen) -> Result<RgbaImage, String> {
let display = CGDisplay::new(screen.id);
capture_rect(screen, display.bounds())
}
pub fn capture_area(screen: &Screen, x: i32, y: i32, width: u32, height: u32) -> Result<RgbaImage, String> {
let display = CGDisplay::new(screen.id);
let origin = display.bounds().origin;
let rect = CGRect {
origin: CGPoint::new(origin.x + x as f64, origin.y + y as f64),
size: CGSize::new(width as f64, height as f64),
};
capture_rect(screen, rect)
}