#How to get Handle<Image> size in pixels?

39 messages · Page 1 of 1 (latest)

lone rapids
#

I am trying to get image size in pixels. currently doing and getting all (1, 1) sizes. (My images are at least 32x32pixels, a lot are bigger):

fn fix_translations(
    mut playing_images: Query<(Entity, &Name, &mut AnimatedImageController, &mut Sprite)>,
    animated_images: Res<Assets<AnimatedImage>>,
    images: Res<Assets<Image>>,
) {
    for (entity, name, animated, sprite) in &playing_images {
        let img = images.get(&sprite.image).unwrap();
        dbg!(name, img.size()); // all sizes are equal to (1, 1)
    }
}

AnimatedImageController is from this library: https://github.com/vleue/vleue_kinetoscope/

#

I need this because I want to draw colored rectangle over the image, and to render the rectangle I need to know how big is the texture.

torpid temple
#

what's img.data.map(|v|v.len()) give you

#

also try the Debug impl of img.texture_descriptor

royal solstice
#

Image::default() sets size to 1,1 and 1px with 255 as all values. Maybe your images are created that way? Do the images work, like render, properly?

royal solstice
#

@lone rapids odd question: if you're animation is a Gif, please open it in a hex editor and share the values of the first 10 bytes in hex format.

asking because the "canvas size" of a gif should be what ultimately ends up as the image.size() if i read the code correctly (bevy_asset -> image -> gif) and its plausible that your gif file is strange in that it has wrong values there. if you want to check directly, theyre little-endian u16: byte 7,8 is width, byte 9,10 is height

lone rapids
#

It seems that it was showing 1, 1 size because asset was not loaded yet (I think).
I now keep printing in update schedule and it shows once correct size, and in next update crashes because Handle<Image>is deleted (I guess it is moved to the GPU?).

Is there any way to handle it elegantly without ugly hacks like trying to get Image size and if it is not None and not 1,1 size then save it for later use?

MRE: https://github.com/df51d/gif_size_problem

// $ file assets/foo.gif
// assets/foo.gif: GIF image data, version 89a, 64 x 64

// First update
[src/main.rs:32:9] img.size() = UVec2(1, 1)
[src/main.rs:32:9] time.elapsed() = 0ns
// Second update
[src/main.rs:32:9] img.size() = UVec2(64, 64)
[src/main.rs:32:9] time.elapsed() = 45.643089ms
// Third update
thread '<unnamed>' panicked at src/main.rs:31:40:
called `Option::unwrap()` on a `None` value

In ideal scenario I would like to know the size when first loading asset because I need to create mesh with it size:

let handle = asset_server.load(format!("images/icons/{}", icon.icon));
let animated_image_controller =
    vleue_kinetoscope::AnimatedImageController::play(handle);
let image_size = ???;
let mesh = meshes.add(Rectangle::from_size(image_size));
lone rapids
#

For now fixed it like that:

fn print(
    mut commands: Commands,
    playing_images: Query<(Entity, &mut AnimatedImageController, &mut Sprite), Without<Mesh2d>>,
    images: Res<Assets<Image>>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    for (entity, _animated_image_controller, sprite) in &playing_images {
        let Some(img) = images.get(&sprite.image) else {
            continue;
        };
        let size = img.size_f32();
        if size.x == 1. || size.y == 1. {
            continue;
        }
        let mesh = meshes.add(Rectangle::from_size(size));
        let material = materials.add(ColorMaterial::from_color(Color::linear_rgba(
            1., 0., 1., 5.,
        )));

        commands.entity(entity).insert((
            Transform::from_translation(size.extend(1.0)),
            Mesh2d(mesh),
            MeshMaterial2d(material),
        ));
    }
}
royal solstice
#

I assume the image gets unloaded because vleu_kinetoscope holds the only strong handle and that gets dropped

#

actually hmm no you aren't using the streaming so it should keep the handles alive... odd, why are you getting empty images then?

#

yeah wtf the non-streaming one is supposed to loop, those images should all exist

#

oh wait you're getting the sprite image, not the AnimatedImage frames, yeah hmm odd

#

it still should be alive because animated_image.frames should store all the strong handles

lone rapids
#

Hmm let me check getting Image from AnimatedImageController then. Maybe it will get me correct size from get go

royal solstice
#

SOLVED IT

#

If an asset is set to the RENDER_WORLD but not the MAIN_WORLD, the asset will be unloaded from the asset server once it’s been extracted and prepared in the render world.

#

thats what it does, vleu_kinetoscope sets RenderAssetUsages::RENDER_WORLD

#

so the image gets unloaded from the main world

lone rapids
#

Well I guess my hack works so I will keep using it. Thanks for help @royal solstice

royal solstice
#

well, Vec<Frame>, but Frame is basically just a Handle<Image>

lone rapids
#

My thinking was that because I am getting it from AnimatedImage directly it will have correct size, but now I am thinking

#

that correct size will be in "current_frame"

#

I will git clone vleue_kinetoscope and make it public field so I can check my hypothesis

royal solstice
#

you could instead listen to AssetEvent and check if event.is_loaded_with_dependencies(animated_image_handle) and only get the sprite image at that point

#

but you basically have to go through the sprite image, as thats the only way to get the handle

#

mainly using the event would allow you to not have to rely on checking each frame just for the single frame where the image is loaded in the main world

#

because nothing will change that the images are only loaded for a single frame in the main world

royal solstice
lone rapids
royal solstice
#

fair enough, maybe you could make an issue for the usecase?

#

like, some way of getting image dimensions

lone rapids
#

Good idea, I will do it when my internet will be back to speed

royal solstice
#

nice