145 lines
4.8 KiB
Rust
145 lines
4.8 KiB
Rust
// 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<u16> {
|
|
OsStr::new(str)
|
|
.encode_wide()
|
|
.chain(Some(0).into_iter())
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
// 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::<BITMAP>() 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::<u8>::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::<BITMAPINFOHEADER>() 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,
|
|
}
|
|
}
|
|
}
|