use crate::common::image::convert_bgra_to_rgba;
use crate::ImageOnHeap;
use anyhow::{ensure, Context, Result};
use core_graphics::display::*;
use core_graphics::image::CGImageRef;
use image::flat::SampleLayout;
use image::{ColorType, FlatSamples};
pub fn capture_window_screenshot(win_id: u64) -> Result<ImageOnHeap> {
let (w, h, channels, mut raw_data) = {
let image = unsafe {
CGDisplay::screenshot(
CGRectNull,
kCGWindowListOptionIncludingWindow | kCGWindowListExcludeDesktopElements,
win_id as u32,
kCGWindowImageNominalResolution
| kCGWindowImageBoundsIgnoreFraming
| kCGWindowImageShouldBeOpaque,
)
}
.context(format!(
"Cannot grab screenshot from CGDisplay of window id {}",
win_id
))?;
let img_ref: &CGImageRef = ℑ
let (_wrong_width, h) = (img_ref.width() as u32, img_ref.height() as u32);
let raw_data: Vec<_> = img_ref.data().to_vec();
let byte_per_row = img_ref.bytes_per_row() as u32;
ensure!(
byte_per_row * h == raw_data.len() as u32,
format!(
"Cannot grab screenshot from CGDisplay of window id {}",
win_id
)
);
let byte_per_pixel = (img_ref.bits_per_pixel() / 8) as u8;
let w = byte_per_row / byte_per_pixel as u32;
(w, h, byte_per_pixel, raw_data)
};
convert_bgra_to_rgba(&mut raw_data);
let color = ColorType::Rgba8;
let buffer = FlatSamples {
samples: raw_data,
layout: SampleLayout::row_major_packed(channels, w, h),
color_hint: Some(color),
};
Ok(ImageOnHeap::new(buffer))
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "e2e_tests")]
use crate::macos::setup;
#[cfg(feature = "e2e_tests")]
use image::save_buffer;
#[test]
#[should_panic(expected = "Cannot grab screenshot from CGDisplay of window id 999999")]
fn should_throw_on_invalid_window_id() {
capture_window_screenshot(9999999).unwrap();
}
#[test]
#[cfg(feature = "e2e_tests")]
fn should_capture_with_cropped_transparent_area() -> Result<()> {
use crate::common::PlatformApi;
use crate::utils::IMG_EXT;
let mut api = setup()?;
let win = 5308;
let image = api.capture_window_screenshot(win)?;
let (width, height) = (image.layout.width, image.layout.height);
dbg!(width, height);
save_buffer(
format!("frame-org-{win}.{IMG_EXT}"),
&image.samples,
image.layout.width,
image.layout.height,
image.color_hint.unwrap(),
)
.context("Cannot save a frame.")?;
api.calibrate(win)?;
let image_cropped = api.capture_window_screenshot(win)?;
assert!(width > image_cropped.layout.width);
save_buffer(
format!("frame-cropped-{win}.{IMG_EXT}"),
&image_cropped.samples,
image_cropped.layout.width,
image_cropped.layout.height,
image_cropped.color_hint.unwrap(),
)
.context("Cannot save a frame.")?;
Ok(())
}
}