Last active
March 7, 2023 23:53
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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