From 43c1493c40448e1b2a6aeee55c1573a44c45a832 Mon Sep 17 00:00:00 2001 From: Philip Kristoffersen Date: Tue, 23 Aug 2022 22:16:57 +0200 Subject: [PATCH] Use custom version of image-rs (#210) This is done to avoid a panic in the current version image rs --- Cargo.lock | 3 +- Cargo.toml | 6 ++- src/testdata/hollow.webp | Bin 0 -> 9326 bytes src/ui/defines.rs | 74 ++++++++++++------------------------ src/ui/ui_image_download.rs | 6 +-- 5 files changed, 33 insertions(+), 56 deletions(-) create mode 100644 src/testdata/hollow.webp diff --git a/Cargo.lock b/Cargo.lock index 840bb59..4e99433 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,8 +1340,7 @@ dependencies = [ [[package]] name = "image" version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964" +source = "git+https://github.com/PhilipK/image?rev=cb66840dd42785c7283206cc9805240501695a61#cb66840dd42785c7283206cc9805240501695a61" dependencies = [ "bytemuck", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index f88f0cf..e0aac75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ steam_shortcuts_util = "^1.1.8" steamgriddb_api = "^0.3.1" sysinfo = "^0.25.2" + [dependencies.dashmap] features = ["serde"] version = "^5.3.4" @@ -32,8 +33,9 @@ version = "^0.19.0" version = "^0.3.23" [dependencies.image] -features = ["png"] -version = "^0.24.3" +features = ["png","webp","jpeg"] +git = "https://github.com/PhilipK/image" +rev = "cb66840dd42785c7283206cc9805240501695a61" [dependencies.reqwest] default_features = false diff --git a/src/testdata/hollow.webp b/src/testdata/hollow.webp new file mode 100644 index 0000000000000000000000000000000000000000..fb0bf5db46f49595522ef124cb15e64947fec2bc GIT binary patch literal 9326 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 Option { - if path.exists() { - if let Ok(data) = std::fs::read(path) { - let load_result = load_image_from_memory(&data); - if load_result.is_err() { - eprintln!("Could not load image at path {:?}", path); - } - return load_result.ok(); - } - } - None - } - fn load_image_from_memory(image_data: &[u8]) -> Result { + pub fn load_image_from_path(path: &std::path::Path) -> Result { + let image = image::io::Reader::open(path)?.decode()?; + let size = [image.width() as _, image.height() as _]; + let image_buffer = image.to_rgba8(); + let pixels = image_buffer.as_flat_samples(); + Ok(egui::ColorImage::from_rgba_unmultiplied( + size, + pixels.as_slice(), + )) + } + + pub fn load_image_from_memory(image_data: &[u8]) -> Result { let image = image::load_from_memory(image_data)?; let size = [image.width() as _, image.height() as _]; let image_buffer = image.to_rgba8(); let pixels = image_buffer.as_flat_samples(); - thread::scope(|s| { - let rgba = pixels.as_slice(); - let is_valid = size[0] * size[1] * 4 == rgba.len(); - if is_valid { - //Wrapping this in a thread, since it has a tendency to panic - let thread_handle = s - .spawn(move || ColorImage::from_rgba_unmultiplied(size, rgba)) - .join(); - match thread_handle { - Ok(value) => Ok(value), - Err(e) => { - println!("Error loading image {:?}", e); - Err(image::ImageError::Decoding( - image::error::DecodingError::new( - image::error::ImageFormatHint::Unknown, - "Could not load image, it panicked while trying", - ), - )) - } - } - } else { - Err(image::ImageError::Decoding( - image::error::DecodingError::new( - image::error::ImageFormatHint::Unknown, - "Image did not have right amount of pixels", - ), - )) - } - }) + Ok(ColorImage::from_rgba_unmultiplied( + size, + pixels.as_slice(), + )) } } @@ -104,18 +74,24 @@ mod tests { #[test] pub fn test_image_load_that_is_broken() { let res = load_image_from_path(std::path::Path::new("src/testdata/brokenimage.webp")); - assert!(res.is_none()); + assert!(res.is_err()); } #[test] pub fn test_image_load_that_works_png() { let res = load_image_from_path(std::path::Path::new("src/testdata/smallpng.png")); - assert!(res.is_some()); + assert!(res.is_ok()); } #[test] pub fn test_image_load_that_works_webp() { let res = load_image_from_path(std::path::Path::new("src/testdata/spider.webp")); - assert!(res.is_some()); + assert!(res.is_ok()); + } + + #[test] + pub fn test_image_load_animated_webp() { + let res = load_image_from_path(std::path::Path::new("src/testdata/hollow.webp")); + assert!(res.is_err()); } } diff --git a/src/ui/ui_image_download.rs b/src/ui/ui_image_download.rs index e5a6a7f..a04c541 100644 --- a/src/ui/ui_image_download.rs +++ b/src/ui/ui_image_download.rs @@ -263,7 +263,7 @@ impl MyEguiApp { TextureState::Downloaded => { //Need to load let image_data = load_image_from_path(&image.thumbnail_path); - if let Some(image_data) = image_data { + if let Ok(image_data) = image_data { let handle = ui.ctx().load_texture( &image_key, image_data, @@ -481,7 +481,7 @@ impl MyEguiApp { let loaded = state.image_handles.contains_key(&key); if !loaded && path.exists() { let image = load_image_from_path(&path); - if let Some(image) = image { + if let Ok(image) = image { let texture = ui .ctx() .load_texture(&key, image, egui::TextureFilter::Linear); @@ -607,7 +607,7 @@ impl MyEguiApp { for image_type in ImageType::all() { let (path, key) = shortcut.key(image_type, Path::new(&user.steam_user_data_folder)); let image = load_image_from_path(&path); - if let Some(image) = image { + if let Ok(image) = image { let texture = ui .ctx() .load_texture(&key, image, egui::TextureFilter::Linear);