image icon indicating copy to clipboard operation
image copied to clipboard

Thread panics on EXR containing NAN

Open gyk opened this issue 1 year ago • 1 comments

Some EXR files might contain NaNs, e.g., AllHalfValues.exr. Calling to_rgba8 on such images causes a panic:

thread 'main' panicked at image-0.25.1\src\color.rs:435:30:
called `Option::unwrap()` on a `None` value

gyk avatar Jul 01 '24 12:07 gyk

Shorter repro:

let img = Rgba32FImage::from_raw(1, 1, vec![1.0 / 0.]).expect("create nan image");
DynamicImage::ImageRgba32F(img).to_rgba8();

fintelia avatar Jul 02 '24 04:07 fintelia

According to my research, there is no defined operation for how to handle NaN when converting to another format. I can open a PR against my branch if the below behavior is agreed upon. Firefox render of the linked sample image image PNG conversion with clamp applied, from the fixed branch out

FlareFlo avatar Nov 15 '24 23:11 FlareFlo

Num traits does not support Positive infinites, Negative infinites also, only subnormal numbers are supported. Usually most hardware flushes NaNs towards negative infinity ( zero for unsigned, max possible negative value for signed ).

awxkee avatar Nov 16 '24 10:11 awxkee

Num traits does not support Positive infinites, Negative infinites also, only subnormal numbers are supported. Usually most hardware flushes NaNs towards negative infinity ( zero for unsigned, max possible negative value for signed ).

Well, in this case the image parses just fine when filtering out NaNs, all other funny values appear to be handled (as this image contains every possible bitrepr)

FlareFlo avatar Nov 16 '24 13:11 FlareFlo

Not really, here two immediate fails

    let img1 = Rgba32FImage::from_raw(1, 1, vec![f32::INFINITY]).expect("create +inf image");
    DynamicImage::ImageRgba32F(img1).to_rgba8();

    let img2 = Rgba32FImage::from_raw(1, 1, vec![f32::NEG_INFINITY]).expect("create -inf image");
    DynamicImage::ImageRgba32F(img2).to_rgba8();

awxkee avatar Nov 16 '24 13:11 awxkee

    let img2 = Rgba32FImage::from_raw(1, 1, vec![f32::NEG_INFINITY]).expect("create -inf image");
    DynamicImage::ImageRgba32F(img2).to_rgba8();

~~I believe this is a tangential issue, as this doesnt work either:~~

    let img2 = Rgba32FImage::from_raw(1, 1, vec![0.0]).expect("create any image");
    DynamicImage::ImageRgba32F(img2).to_rgba8();

~~(fails on the expect)~~ see below comment

FlareFlo avatar Nov 16 '24 14:11 FlareFlo

Specifically, image_buffer_len yields Some(4) with input 1,1. The shorter repro was simply bugged as it did not take the 4 color channels into account. image

FlareFlo avatar Nov 16 '24 14:11 FlareFlo

    let img2 = Rgba32FImage::from_raw(1,1, vec![f32::NEG_INFINITY, f32::INFINITY, f32::NAN, f32::MAX]).expect("create funny image");
    dbg!(DynamicImage::ImageRgba32F(img2).to_rgba8());

runs perfectly fine

[src/main.rs:9:5] DynamicImage::ImageRgba32F(img2).to_rgba8() = ImageBuffer {
    width: 1,
    height: 1,
    _phantom: PhantomData<image::color::Rgba<u8>>,
    data: [
        0,
        255,
        1,
        255,
    ],
}

FlareFlo avatar Nov 16 '24 14:11 FlareFlo

Fixed by #2381

Shnatsel avatar Jun 18 '25 01:06 Shnatsel