fix: detect SVG icons by content
This commit is contained in:
parent
d4d71fd53e
commit
0304f1d92e
3 changed files with 55 additions and 11 deletions
|
|
@ -166,6 +166,7 @@ zbus = { workspace = true, optional = true }
|
|||
float-cmp = "0.10.0"
|
||||
ron = { workspace = true, optional = true }
|
||||
enumflags2 = "0.7.12"
|
||||
roxmltree = "0.20"
|
||||
|
||||
# Enable DBus feature on Linux targets
|
||||
[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies]
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ use super::Icon;
|
|||
use crate::widget::{image, svg};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::hash::Hash;
|
||||
use std::path::PathBuf;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[must_use]
|
||||
#[derive(Clone, Debug, Hash, derive_setters::Setters)]
|
||||
|
|
@ -31,6 +33,52 @@ pub enum Data {
|
|||
Svg(svg::Handle),
|
||||
}
|
||||
|
||||
enum SvgSource {
|
||||
Path,
|
||||
Bytes(Vec<u8>),
|
||||
}
|
||||
|
||||
fn svg_source(path: &Path) -> Option<SvgSource> {
|
||||
if path
|
||||
.extension()
|
||||
.and_then(OsStr::to_str)
|
||||
.is_some_and(|extension| extension.eq_ignore_ascii_case("svg"))
|
||||
{
|
||||
return Some(SvgSource::Path);
|
||||
}
|
||||
|
||||
let Ok(mut file) = File::open(path) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let Ok(metadata) = file.metadata() else {
|
||||
return None;
|
||||
};
|
||||
const MAX_SVG_SIZE: u64 = 16 * 1024 * 1024;
|
||||
if !metadata.file_type().is_file() || metadata.len() > MAX_SVG_SIZE {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut prefix = [0; 32];
|
||||
let Ok(length) = file.read(&mut prefix) else {
|
||||
return None;
|
||||
};
|
||||
let prefix = &prefix[..length];
|
||||
|
||||
if ::image::guess_format(prefix).is_ok() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut bytes = Vec::with_capacity(metadata.len() as usize);
|
||||
bytes.extend_from_slice(prefix);
|
||||
if file.read_to_end(&mut bytes).is_err() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let document = roxmltree::Document::parse(std::str::from_utf8(&bytes).ok()?).ok()?;
|
||||
(document.root_element().tag_name().name() == "svg").then_some(SvgSource::Bytes(bytes))
|
||||
}
|
||||
|
||||
/// Create an icon handle from its path.
|
||||
pub fn from_path(path: PathBuf) -> Handle {
|
||||
Handle {
|
||||
|
|
@ -38,10 +86,10 @@ pub fn from_path(path: PathBuf) -> Handle {
|
|||
.file_stem()
|
||||
.and_then(OsStr::to_str)
|
||||
.is_some_and(|name| name.ends_with("-symbolic")),
|
||||
data: if path.extension().is_some_and(|ext| ext == OsStr::new("svg")) {
|
||||
Data::Svg(svg::Handle::from_path(path))
|
||||
} else {
|
||||
Data::Image(image::Handle::from_path(path))
|
||||
data: match svg_source(&path) {
|
||||
Some(SvgSource::Path) => Data::Svg(svg::Handle::from_path(path)),
|
||||
Some(SvgSource::Bytes(bytes)) => Data::Svg(svg::Handle::from_memory(bytes)),
|
||||
None => Data::Image(image::Handle::from_path(path)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
use super::{Handle, Icon};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -138,11 +137,7 @@ impl Named {
|
|||
Handle {
|
||||
symbolic: self.symbolic,
|
||||
data: if let Some(path) = self.path() {
|
||||
if path.extension().is_some_and(|ext| ext == OsStr::new("svg")) {
|
||||
super::Data::Svg(iced_core::svg::Handle::from_path(path))
|
||||
} else {
|
||||
super::Data::Image(iced_core::image::Handle::from_path(path))
|
||||
}
|
||||
super::from_path(path).data
|
||||
} else {
|
||||
super::bundle::get(&name).unwrap_or_else(|| {
|
||||
let bytes: &'static [u8] = &[];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue