Add ImageFormatSetting::Guess to image loader (#13575)

# 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<AssetServer>) {
    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 <mockersf@gmail.com>
This commit is contained in:
Alix Bott 2024-05-31 01:57:22 +02:00 committed by GitHub
parent 06f733b16f
commit 31955cc78b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 0 deletions

View file

@ -109,6 +109,26 @@ impl ImageFormat {
ImageFormat::Basis | ImageFormat::Ktx2 => return None,
})
}
pub fn from_image_crate_format(format: image::ImageFormat) -> Option<ImageFormat> {
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)]

View file

@ -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"))]