// https://github.com/emilk/egui/issues/920 #[cfg(not(windows))] pub fn load_app_icon(_icon_name: &str) -> eframe::egui::IconData { let (icon_rgba, icon_width, icon_height) = { let icon = include_bytes!("../../icons/soundboard.ico"); let image = image::load_from_memory(icon) .expect("Failed to open icon path") .into_rgba8(); let (width, height) = image.dimensions(); let rgba = image.into_raw(); (rgba, width, height) }; eframe::egui::IconData { rgba: icon_rgba, width: icon_width, height: icon_height, } } #[cfg(windows)] pub use from_windows::load_app_icon; #[cfg(windows)] mod from_windows { use std::{ffi::OsStr, os::windows::ffi::OsStrExt}; use eframe::egui; use windows::{ core::PCWSTR, Win32::{ Graphics::Gdi::{ CreateCompatibleDC, DeleteDC, GetDIBits, GetObjectA, SelectObject, BITMAP, BITMAPINFO, BITMAPINFOHEADER, DIB_RGB_COLORS, }, System::LibraryLoader::GetModuleHandleW, UI::WindowsAndMessaging::{ GetIconInfo, LoadImageW, HICON, ICONINFO, IMAGE_ICON, LR_DEFAULTCOLOR, }, }, }; fn to_wstring(str: &str) -> Vec { OsStr::new(str) .encode_wide() .chain(Some(0).into_iter()) .collect::>() } // Grab the icon from the exe and hand it over to egui pub fn load_app_icon(icon_name: &str) -> egui::IconData { let (mut buffer, width, height) = unsafe { let resource_name = to_wstring(icon_name); let h_instance = GetModuleHandleW(None).unwrap(); let icon = LoadImageW( h_instance, PCWSTR(resource_name.as_ptr()), IMAGE_ICON, 512, 512, LR_DEFAULTCOLOR, ) .unwrap(); let mut icon_info = ICONINFO::default(); GetIconInfo(HICON(icon.0), &mut icon_info as *mut _).expect("Failed to load icon info"); let mut bitmap = BITMAP::default(); GetObjectA( icon_info.hbmColor, std::mem::size_of::() as i32, Some(&mut bitmap as *mut _ as *mut _), ); let width = bitmap.bmWidth; let height = bitmap.bmHeight; let b_size = (width * height * 4) as usize; let mut buffer = Vec::::with_capacity(b_size); let h_dc = CreateCompatibleDC(None); let h_bitmap = SelectObject(h_dc, icon_info.hbmColor); let mut bitmap_info = BITMAPINFO::default(); bitmap_info.bmiHeader.biSize = std::mem::size_of::() as u32; bitmap_info.bmiHeader.biWidth = width; bitmap_info.bmiHeader.biHeight = height; bitmap_info.bmiHeader.biPlanes = 1; bitmap_info.bmiHeader.biBitCount = 32; bitmap_info.bmiHeader.biCompression = 0; bitmap_info.bmiHeader.biSizeImage = 0; let res = GetDIBits( h_dc, icon_info.hbmColor, 0, height as u32, Some(buffer.spare_capacity_mut().as_mut_ptr() as *mut _), &mut bitmap_info as *mut _, DIB_RGB_COLORS, ); if res == 0 { panic!("Failed to get RGB DI bits"); } SelectObject(h_dc, h_bitmap); let _ = DeleteDC(h_dc); assert_eq!( bitmap_info.bmiHeader.biSizeImage as usize, b_size, "returned biSizeImage must equal to b_size" ); // set the new size buffer.set_len(bitmap_info.bmiHeader.biSizeImage as usize); (buffer, width as u32, height as u32) }; // RGBA -> BGRA for pixel in buffer.as_mut_slice().chunks_mut(4) { pixel.swap(0, 2); } // Flip the image vertically let row_size = width as usize * 4; // number of pixels in each row let row_count = buffer.len() as usize / row_size; // number of rows in the image for row in 0..row_count / 2 { // loop through half of the rows let start = row * row_size; // index of the start of the current row let end = (row_count - row - 1) * row_size; // index of the end of the current row for i in 0..row_size { buffer.swap(start + i, end + i); } } egui::IconData { rgba: buffer, width, height, } } }