RustでMacアプリケーションのアイコンを取得する
普通にinfo.plistからアイコンファイル名取得して取ってきたほうが楽...?
2023/1/13
とりあえず動くものは書けた
base64文字列にエンコードしてる
文字列スライスと文字列の使い分けができない
code: rust
use icns::{IconFamily, IconType};
use regex::Regex;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
use std::path::Path;
use base64;
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
// info.plistからアイコンファイルのパスを取得する
fn get_app_icon_path(path: String) -> Option<String> {
if let Ok(lines) = read_lines(format!("{}/Contents/Info.plist", path)) {
let mut found = false;
let pat = Regex::new("</?string>").unwrap();
for line in lines.flatten() {
if found {
let s = pat.replace_all(&line, "");
return Some(format!(
"{}/Contents/Resources/{}",
path,
String::from(s).trim()
));
} else if line.contains("CFBundleIconFile") {
found = true;
}
}
}
None
}
fn calc_icon_size(icon: IconType) -> u32 {
icon.pixel_width() * icon.pixel_height() * icon.pixel_density()
}
// IconFamilyから最小のものをbase64文字列にエンコードして表示
fn icon_to_base64(path: String) {
let file = BufReader::new(File::open(path).unwrap());
let icon_family = IconFamily::read(file).unwrap();
let mut available = icon_family.available_icons();
let init = available.pop().unwrap();
let icon_type = available.into_iter().fold(init, |acc, cur| {
if calc_icon_size(acc) < calc_icon_size(cur) {
acc
} else {
cur
}
});
let image = icon_family.get_icon_with_type(icon_type).unwrap();
let mut buf = vec![];
image.write_png(&mut buf).unwrap();
let res = base64::encode(&buf);
println!("{}", res);
}
fn main() {
if let Some(res) = get_app_icon_path(String::from("/Applications/Google Chrome.app")) {
icon_to_base64(res);
}
}