From 31955cc78bd3865fd7e69dd0a3794f18c1009c6a Mon Sep 17 00:00:00 2001 From: Alix Bott Date: Fri, 31 May 2024 01:57:22 +0200 Subject: [PATCH] Add ImageFormatSetting::Guess to image loader (#13575) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective - Allow using image assets that don't have an extensions and whose format is unknown. This is useful for loading images from arbitrary HTTP URLs. ## Solution - This PR adds a new variant to `ImageFormatSetting` called `Guess`. The loader will use `image::guess_format` to deduce the format based on the content of the file. ## Testing - I locally removed the extension of bevy_bird_dark, and ran a modified version of the `sprite` example: ```rust //! Displays a single [`Sprite`], created from an image. use bevy::{ prelude::*, render::texture::{ImageFormatSetting, ImageLoaderSettings}, }; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands, asset_server: Res) { commands.spawn(Camera2dBundle::default()); commands.spawn(SpriteBundle { texture: asset_server .load_with_settings("branding/bevy_bird_dark", |s: &mut ImageLoaderSettings| { s.format = ImageFormatSetting::Guess }), ..default() }); } ``` ## Changelog ### Added `ImageFormatSetting::Guess` to automatically guess the format of an image asset from its content. Co-authored-by: François Mockers --- crates/bevy_render/src/texture/image.rs | 20 +++++++++++++++++++ .../bevy_render/src/texture/image_loader.rs | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/crates/bevy_render/src/texture/image.rs b/crates/bevy_render/src/texture/image.rs index 4b0a46bd3a..e951ff83a8 100644 --- a/crates/bevy_render/src/texture/image.rs +++ b/crates/bevy_render/src/texture/image.rs @@ -109,6 +109,26 @@ impl ImageFormat { ImageFormat::Basis | ImageFormat::Ktx2 => return None, }) } + + pub fn from_image_crate_format(format: image::ImageFormat) -> Option { + Some(match format { + image::ImageFormat::Avif => ImageFormat::Avif, + image::ImageFormat::Bmp => ImageFormat::Bmp, + image::ImageFormat::Dds => ImageFormat::Dds, + image::ImageFormat::Farbfeld => ImageFormat::Farbfeld, + image::ImageFormat::Gif => ImageFormat::Gif, + image::ImageFormat::OpenExr => ImageFormat::OpenExr, + image::ImageFormat::Hdr => ImageFormat::Hdr, + image::ImageFormat::Ico => ImageFormat::Ico, + image::ImageFormat::Jpeg => ImageFormat::Jpeg, + image::ImageFormat::Png => ImageFormat::Png, + image::ImageFormat::Pnm => ImageFormat::Pnm, + image::ImageFormat::Tga => ImageFormat::Tga, + image::ImageFormat::Tiff => ImageFormat::Tiff, + image::ImageFormat::WebP => ImageFormat::WebP, + _ => return None, + }) + } } #[derive(Asset, Reflect, Debug, Clone)] diff --git a/crates/bevy_render/src/texture/image_loader.rs b/crates/bevy_render/src/texture/image_loader.rs index 6bd906c1d0..3f5f4e3124 100644 --- a/crates/bevy_render/src/texture/image_loader.rs +++ b/crates/bevy_render/src/texture/image_loader.rs @@ -51,6 +51,7 @@ pub enum ImageFormatSetting { #[default] FromExtension, Format(ImageFormat), + Guess, } #[derive(Serialize, Deserialize, Debug)] @@ -100,6 +101,18 @@ impl AssetLoader for ImageLoader { ImageType::Extension(ext) } ImageFormatSetting::Format(format) => ImageType::Format(format), + ImageFormatSetting::Guess => { + let format = image::guess_format(&bytes).map_err(|err| FileTextureError { + error: err.into(), + path: format!("{}", load_context.path().display()), + })?; + ImageType::Format(ImageFormat::from_image_crate_format(format).ok_or_else( + || FileTextureError { + error: TextureError::UnsupportedTextureFormat(format!("{format:?}")), + path: format!("{}", load_context.path().display()), + }, + )?) + } }; Ok(Image::from_buffer( #[cfg(all(debug_assertions, feature = "dds"))]