Skip to content

Instantly share code, notes, and snippets.

@nullmastermind
Last active March 7, 2023 23:53
Show Gist options
  • Save nullmastermind/edcbb79ca4e7457663898588c660b428 to your computer and use it in GitHub Desktop.
Save nullmastermind/edcbb79ca4e7457663898588c660b428 to your computer and use it in GitHub Desktop.
Capture screen windows in rustlang. Speed, memory optimize, opencv mat. This class is utilized within my Valorant cheating tools
use opencv::core::Mat;
use opencv::imgcodecs::{imdecode, IMREAD_COLOR};
pub use opencv::prelude::MatTraitConstManual;
use png::{BitDepth, ColorType, Encoder};
use std::f64;
use std::mem::size_of;
use windows::Win32::Graphics::Gdi::{
BitBlt, CreateCompatibleBitmap, CreateCompatibleDC, CreatedHDC, DeleteObject, GetDC, GetDIBits,
SelectObject, BITMAPINFO, BITMAPINFOHEADER, BI_COMPRESSION, CAPTUREBLT, DIB_RGB_COLORS,
HBITMAP, HDC, SRCCOPY,
};
use windows::Win32::UI::WindowsAndMessaging;
use windows::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SYSTEM_METRICS_INDEX};
#[derive(Debug)]
pub struct Capture {
src_dc: HDC,
mem_dc: CreatedHDC,
bmi: BITMAPINFO,
cap_box: (i32, i32, i32, i32),
monitor_size: (i32, i32),
data: Vec<u8>,
bmp: HBITMAP,
}
impl Capture {
pub fn new() -> Capture {
unsafe {
let src_dc = GetDC(WindowsAndMessaging::HWND_DESKTOP);
let mem_dc = CreateCompatibleDC(src_dc);
let mut bmi = BITMAPINFO::default();
bmi.bmiHeader.biSize = size_of::<BITMAPINFOHEADER>() as u32;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_COMPRESSION(0);
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
let monitor_size = Capture::get_monitor_size();
let bmp = HBITMAP::default();
let cap_box = (0, 0, 0, 0);
let data = vec![];
Capture {
src_dc,
mem_dc,
bmi,
cap_box,
monitor_size,
data,
bmp,
}
}
}
pub fn get_capture(&mut self, w: i32, h: i32) -> Vec<u8> {
unsafe {
let area = (
w,
h,
(self.monitor_size.0 - w) / 2,
(self.monitor_size.1 - h) / 2,
);
if self.cap_box != area {
self.cap_box = area;
self.bmi.bmiHeader.biWidth = w;
self.bmi.bmiHeader.biHeight = -h;
if self.bmp != HBITMAP::default() {
DeleteObject(self.bmp);
}
self.data = vec![0u8; (w * h) as usize * 4];
self.bmp = CreateCompatibleBitmap(self.src_dc, w, h);
SelectObject(self.mem_dc, self.bmp);
}
BitBlt(
self.mem_dc,
0,
0,
w,
h,
self.src_dc,
area.2,
area.3,
SRCCOPY | CAPTUREBLT,
);
let bits = GetDIBits(
self.mem_dc,
self.bmp,
0,
h as u32,
Some(self.data.as_mut_ptr() as *mut _),
&mut self.bmi,
DIB_RGB_COLORS,
);
assert_eq!(bits, h);
};
self.data.to_vec()
}
fn rgb_to_hsv(r: u8, g: u8, b: u8) -> (f64, f64, f64) {
let r = r as f64 / 255f64;
let g = g as f64 / 255f64;
let b = b as f64 / 255f64;
let cmax = f64::max(r, f64::max(g, b));
let cmin = f64::min(r, f64::min(g, b));
let diff = cmax - cmin;
let v = cmax * 100f64;
let mut h = -1f64;
if cmax == cmin {
h = 0f64;
} else if cmax == r {
h = (60f64 * ((g - b) / diff) + 360f64) % 360f64;
} else if cmax == g {
h = (60f64 * ((b - r) / diff) + 120f64) % 360f64;
} else if cmax == b {
h = (60f64 * ((r - g) / diff) + 240f64) % 360f64;
}
if cmax == 0f64 {
return (h, 0f64, v);
}
(h, (diff / cmax) * 100f64, v)
}
pub fn get_mat(data: Vec<u8>, w: i32, h: i32) -> anyhow::Result<Mat> {
let mut bytes = vec![0u8; (data.len() / 4) * 3];
let mut buffer = Vec::new();
// BGRA to RGB
for i in (0..data.len()).step_by(4) {
let index = (i / 4) * 3;
let r = data[i + 2];
let g = data[i + 1];
let b = data[i];
// Handle hsv filter
Capture::rgb_to_hsv(r, g, b);
bytes[index] = r;
bytes[index + 1] = g;
bytes[index + 2] = b;
}
let mut encoder = Encoder::new(&mut buffer, w as u32, h as u32);
encoder.set_color(ColorType::Rgb);
encoder.set_depth(BitDepth::Eight);
let mut writer = encoder.write_header()?;
writer.write_image_data(&bytes)?;
writer.finish()?;
let src = Mat::from_slice::<u8>(buffer.as_slice())?;
let mat = imdecode(&src, IMREAD_COLOR)?;
// let mut mat1 = Mat::default();
// cvt_color(&mat, &mut mat1, COLOR_RGB2RGBA, 0).unwrap();
Ok(mat)
}
pub fn get_monitor_size() -> (i32, i32) {
let w = unsafe { GetSystemMetrics(SYSTEM_METRICS_INDEX(0)) };
let h = unsafe { GetSystemMetrics(SYSTEM_METRICS_INDEX(1)) };
(w, h)
}
}
// init first
let mut capture = Capture::new();
// use this spell in every frame
let cap = capture.get_capture(224, 224);
match Capture::get_mat(cap, 224, 224) {
Ok(mat) => {
// mat is ur OpenCV mat
}
Err(_) => {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment