soundboard/src/icon.rs

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,
}
}
}