use windows_sys::Win32::Foundation::HWND;
use windows_sys::Win32::Graphics::Gdi::{
BI_RGB, BITMAPINFO, BITMAPINFOHEADER, CAPTUREBLT, CreateCompatibleBitmap, CreateCompatibleDC,
DIB_RGB_COLORS, DeleteDC, DeleteObject, GetDC, GetDIBits, ReleaseDC, SRCCOPY, SelectObject,
};
use windows_sys::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN};
pub fn pixels_matching(red: u8, green: u8, blue: u8) -> Option<usize> {
let width = unsafe { GetSystemMetrics(SM_CXSCREEN) };
let height = unsafe { GetSystemMetrics(SM_CYSCREEN) };
if width <= 0 || height <= 0 {
return None;
}
let pixels = capture(width, height)?;
Some(
pixels
.chunks_exact(4)
.filter(|pixel| pixel[0] == blue && pixel[1] == green && pixel[2] == red)
.count(),
)
}
fn capture(width: i32, height: i32) -> Option<Vec<u8>> {
let screen = unsafe { GetDC(std::ptr::null_mut::<HWND>() as HWND) };
if screen.is_null() {
return None;
}
let memory = unsafe { CreateCompatibleDC(screen) };
let bitmap = unsafe { CreateCompatibleBitmap(screen, width, height) };
let pixels = if memory.is_null() || bitmap.is_null() {
None
} else {
read_into_buffer(screen, memory, bitmap, width, height)
};
unsafe {
if !bitmap.is_null() {
DeleteObject(bitmap.cast());
}
if !memory.is_null() {
DeleteDC(memory);
}
ReleaseDC(std::ptr::null_mut::<HWND>() as HWND, screen);
}
pixels
}
fn read_into_buffer(
screen: windows_sys::Win32::Graphics::Gdi::HDC,
memory: windows_sys::Win32::Graphics::Gdi::HDC,
bitmap: windows_sys::Win32::Graphics::Gdi::HBITMAP,
width: i32,
height: i32,
) -> Option<Vec<u8>> {
let previous = unsafe { SelectObject(memory, bitmap.cast()) };
let copied = unsafe {
windows_sys::Win32::Graphics::Gdi::BitBlt(
memory,
0,
0,
width,
height,
screen,
0,
0,
SRCCOPY | CAPTUREBLT,
)
};
let mut info: BITMAPINFO = unsafe { std::mem::zeroed() };
info.bmiHeader = BITMAPINFOHEADER {
biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32,
biWidth: width,
biHeight: -height,
biPlanes: 1,
biBitCount: 32,
biCompression: BI_RGB,
biSizeImage: 0,
biXPelsPerMeter: 0,
biYPelsPerMeter: 0,
biClrUsed: 0,
biClrImportant: 0,
};
let mut buffer = vec![0u8; (width as usize) * (height as usize) * 4];
let rows = unsafe {
GetDIBits(
memory,
bitmap,
0,
height as u32,
buffer.as_mut_ptr().cast(),
&mut info,
DIB_RGB_COLORS,
)
};
unsafe { SelectObject(memory, previous) };
if copied == 0 || rows == 0 {
return None;
}
Some(buffer)
}