use bevy::{
app::{App, Plugin},
asset::{io::Reader, AssetLoader, LoadContext, RenderAssetUsages},
prelude::*,
};
use bevy_reflect::TypePath;
use wgpu_types::{Extent3d, TextureDimension, TextureFormat};
use jpeg2k::{error, Image, ImageData, ImagePixelData};
#[derive(Default, TypePath)]
pub struct Jpeg2KAssetLoader;
impl AssetLoader for Jpeg2KAssetLoader {
type Asset = bevy::image::Image;
type Settings = ();
type Error = anyhow::Error;
async fn load(
&self,
reader: &mut dyn Reader,
_settings: &Self::Settings,
_load_context: &mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
let image = Image::from_bytes(&bytes)?;
let txt = image_to_texture(image)?;
Ok(txt)
}
fn extensions(&self) -> &[&str] {
&["j2k", "jp2", "j2c", "jpc"]
}
}
pub fn image_to_texture(img: Image) -> error::Result<bevy::image::Image> {
let ImageData {
width,
height,
data,
..
} = match img.num_components() {
1 | 4 => img.get_pixels(None)?,
3 => img.get_pixels(Some(u32::MAX))?,
num => {
return Err(error::Error::UnsupportedComponentsError(num));
}
};
let (format, data) = match data {
ImagePixelData::L8(data) => (TextureFormat::R8Unorm, data),
ImagePixelData::La8(data) => (TextureFormat::Rg8Unorm, data),
ImagePixelData::Rgba8(data) => (TextureFormat::Rgba8UnormSrgb, data),
_ => {
return Err(error::Error::UnknownFormatError(format!(
"Unsupported pixel data."
)));
}
};
Ok(bevy::image::Image::new(
Extent3d {
width,
height,
depth_or_array_layers: 1,
},
TextureDimension::D2,
data,
format,
RenderAssetUsages::all(),
))
}
#[derive(Default, Clone, Debug)]
pub struct Jpeg2KPlugin;
impl Plugin for Jpeg2KPlugin {
fn build(&self, app: &mut App) {
app.init_asset_loader::<Jpeg2KAssetLoader>();
}
}