bevy_mod_krita/
loader.rs

1use std::io::{Cursor, Read};
2
3use bevy_asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext};
4use bevy_ecs::world::{FromWorld, World};
5use bevy_render::{
6    render_asset::RenderAssetUsages,
7    texture::{CompressedImageFormats, Image, ImageSampler, ImageType},
8};
9use zip::ZipArchive;
10
11/// An asset loader to load Krita's `.kra` files.
12#[derive(Debug, Clone)]
13pub struct KritaDocumentLoader;
14
15impl AssetLoader for KritaDocumentLoader {
16    type Asset = Image;
17    type Settings = ();
18    type Error = anyhow::Error;
19
20    fn extensions(&self) -> &[&str] {
21        &["kra"]
22    }
23
24    fn load<'a>(
25        &'a self,
26        reader: &'a mut Reader,
27        _settings: &'a Self::Settings,
28        #[allow(unused_variables)] load_context: &'a mut LoadContext,
29    ) -> bevy_asset::BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
30        Box::pin(async move {
31            // TODO: Improve error handling
32
33            let mut bytes = Vec::new();
34            reader.read_to_end(&mut bytes).await?;
35
36            // `.kra` files are basically just `.zip` files, try to read the ZIP archive
37            let reader = Cursor::new(bytes);
38            let mut archive = ZipArchive::new(reader)?;
39
40            // `.kra` files contain a file `mergedimage.png` which contains the rendered image
41            // See <https://docs.krita.org/en/general_concepts/file_formats/file_kra.html>
42            let mut merged_image = archive.by_name("mergedimage.png")?;
43
44            let mut image_bytes = Vec::<u8>::new();
45            merged_image.read_to_end(&mut image_bytes)?;
46
47            Ok(Image::from_buffer(
48                #[cfg(all(debug_assertions, feature = "dds"))]
49                load_context.path().display().to_string(),
50                &image_bytes,
51                ImageType::Extension("png"),
52                // TODO: Check what to put here
53                CompressedImageFormats::all(),
54                // TODO: Check if it's srgb
55                true,
56                ImageSampler::Default,
57                // TODO: Make this configurable
58                RenderAssetUsages::default(),
59            )?)
60        })
61    }
62}
63
64impl FromWorld for KritaDocumentLoader {
65    fn from_world(_world: &mut World) -> Self {
66        Self
67    }
68}