inflation / jpegxl-rs

GNU General Public License v3.0
56 stars 11 forks source link

Decode failed for some images #29

Closed Isotr0py closed 11 months ago

Isotr0py commented 11 months ago

When I use the decoder from jpegxl-rs crate to decode a specific jxl image, the code panicked at the decoding processing.

   Compiling jxl_rs_test v0.1.0 (/mnt/g/Rust/dev/jxl_rs_test)
    Finished dev [unoptimized + debuginfo] target(s) in 14.81s
     Running `target/debug/jxl_rs_test`
Buffer: 740
thread 'main' panicked at src/main.rs:15:76:
called `Result::unwrap()` on an `Err` value: InvalidInput
stack backtrace:
   0: rust_begin_unwind
             at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:595:5
   1: core::panicking::panic_fmt
             at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/panicking.rs:67:14
   2: core::result::unwrap_failed
             at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/result.rs:1652:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/result.rs:1077:23
   4: jxl_rs_test::main
             at ./src/main.rs:15:52
   5: core::ops::function::FnOnce::call_once
             at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

However, when I use the djxl to decode it, the image can be decoded to png format normally.

$ djxl 2021-08_wwwwwwww.jxl art.png
JPEG XL decoder v0.8.2 954b460 [AVX2,SSE4,SSSE3,Unknown]
Read 740 compressed bytes.
Decoded to pixels.
800 x 600, 17.33 MP/s [17.33, 17.33], 1 reps, 6 threads.

So it seems that the image isn't broken, I wonder if there is a bug in the crate. The image and the Rust code are shown below:

Image

2021-08_wwwwwwww.jxl

Rust code

use jpegxl_rs::decode::Metadata;
use jpegxl_rs::decoder_builder;

use std::fs::File;
use std::io::Read;

fn main() {
    let mut f = File::open("2021-08_wwwwwwww.jxl").unwrap();
    let mut buffer = Vec::new();
    // read the whole file
    f.read_to_end(&mut buffer).unwrap();
    let decoder = decoder_builder().build().unwrap();
    println!("Buffer: {:?}", buffer.len());
    let (Metadata { width, height, ..}, _pixels) = decoder.decode(&buffer).unwrap();
    println!("width:{:?}, height:{:?}",width,height);
}
Isotr0py commented 11 months ago

It seems that all failed images are non-8-bit RGB. Will this cause the panicky?

$ jxlinfo 2021-08_wwwwwwww.jxl
JPEG XL image, 800x600, (possibly) lossless, 2-bit RGB
Color space: RGB, D65, sRGB primaries, sRGB transfer function, rendering intent: Relative

$ jxlinfo 2022-11-iceberg.jxl
JPEG XL image, 2048x2048, (possibly) lossless, 10-bit RGB
Color space: RGB, D65, sRGB primaries, sRGB transfer function, rendering intent: Relative
inflation commented 11 months ago

Hmm… Not sure what a 2-bit RGB image means. You can try to enable vendored feature and see if any error reported by libjxl itself.

inflation commented 11 months ago

I checked again that error only reported on invalid magic bytes at the beginning. djxl maybe more tolerate.

Isotr0py commented 11 months ago

Hmm… Not sure what a 2-bit RGB image means. You can try to enable vendored feature and see if any error reported by libjxl itself.

I have enabled vendored and RUST_BACKTRACE=full, and it seems that the error is just reported by <unknown> instead of libjxl itself.

thread 'main' panicked at src/main.rs:15:75:
called `Result::unwrap()` on an `Err` value: InvalidInput
stack backtrace:
   0:     0x55b83d104fcc - std::backtrace_rs::backtrace::libunwind::trace::he43a6a3949163f8c
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x55b83d104fcc - std::backtrace_rs::backtrace::trace_unsynchronized::h50db52ca99f692e7
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x55b83d104fcc - std::sys_common::backtrace::_print_fmt::hd37d595f2ceb2d3c
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/sys_common/backtrace.rs:67:5
   3:     0x55b83d104fcc - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h678bbcf9da6d7d75
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/sys_common/backtrace.rs:44:22
   4:     0x55b83d124b6c - core::fmt::rt::Argument::fmt::h3a159adc080a6fc9
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/fmt/rt.rs:138:9
   5:     0x55b83d124b6c - core::fmt::write::hb8eaf5a8e45a738e
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/fmt/mod.rs:1094:21
   6:     0x55b83d102d3e - std::io::Write::write_fmt::h9663fe36b2ee08f9
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/io/mod.rs:1714:15
   7:     0x55b83d104db4 - std::sys_common::backtrace::_print::hcd4834796ee88ad2
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/sys_common/backtrace.rs:47:5
   8:     0x55b83d104db4 - std::sys_common::backtrace::print::h1360e9450e4f922a
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/sys_common/backtrace.rs:34:9
   9:     0x55b83d106373 - std::panicking::default_hook::{{closure}}::h2609fa95cd5ab1f4
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:270:22
  10:     0x55b83d10608c - std::panicking::default_hook::h6d75f5747cab6e8d
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:290:9
  11:     0x55b83d1068f9 - std::panicking::rust_panic_with_hook::h57e78470c47c84de
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:707:13
  12:     0x55b83d1067f7 - std::panicking::begin_panic_handler::{{closure}}::h3dfd2453cf356ecb
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:599:13
  13:     0x55b83d1054f6 - std::sys_common::backtrace::__rust_end_short_backtrace::hdb177d43678e4d7e
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/sys_common/backtrace.rs:170:18
  14:     0x55b83d106542 - rust_begin_unwind
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:595:5
  15:     0x55b83ce001c3 - core::panicking::panic_fmt::hd1e971d8d7c78e0e
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/panicking.rs:67:14
  16:     0x55b83ce0063a - core::result::unwrap_failed::hccb456d39e9c31fc
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/result.rs:1652:5
  17:     0x55b83ce0215b - core::result::Result<T,E>::unwrap::hfa2345e994a1f64d
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/result.rs:1077:23
  18:     0x55b83ce01af3 - jxl_rs_test::main::h94e8efc83d620c61
                               at /mnt/g/Rust/dev/jxl_rs_test/src/main.rs:15:51
  19:     0x55b83ce022cb - core::ops::function::FnOnce::call_once::h8aef928f33e7245e
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/ops/function.rs:250:5
  20:     0x55b83ce0220e - std::sys_common::backtrace::__rust_begin_short_backtrace::h6135b8a093837ea2
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/sys_common/backtrace.rs:154:18
  21:     0x55b83ce02281 - std::rt::lang_start::{{closure}}::hef3c298c1f05f9f8
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/rt.rs:166:18
  22:     0x55b83d100a3b - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hbcc4f8a3f5ada78c
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/ops/function.rs:284:13
  23:     0x55b83d100a3b - std::panicking::try::do_call::he5f117a9e13dadde
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:502:40
  24:     0x55b83d100a3b - std::panicking::try::h2f3af9afce3a0443
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:466:19
  25:     0x55b83d100a3b - std::panic::catch_unwind::h6d6c387f38ef05ea
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panic.rs:142:14
  26:     0x55b83d100a3b - std::rt::lang_start_internal::{{closure}}::h6ca09d5905711415
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/rt.rs:148:48
  27:     0x55b83d100a3b - std::panicking::try::do_call::ha9fd18ea06654a4b
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:502:40
  28:     0x55b83d100a3b - std::panicking::try::hda5c2a4432362341
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:466:19
  29:     0x55b83d100a3b - std::panic::catch_unwind::h440f731b142bc235
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panic.rs:142:14
  30:     0x55b83d100a3b - std::rt::lang_start_internal::hc0b4e50f058f62ce
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/rt.rs:148:20
  31:     0x55b83ce0225a - std::rt::lang_start::hade78da4ae7ea325
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/rt.rs:165:17
  32:     0x55b83ce01bee - main
  33:     0x7ff043aa6d90 - <unknown>
  34:     0x7ff043aa6e40 - __libc_start_main
  35:     0x55b83ce018a5 - _start
  36:                0x0 - <unknown>
Isotr0py commented 11 months ago

It seems that image starts with the bytes 0xFF0A (the JPEG marker for "start of JPEG XL codestream" according to libjxl doc) will fail in decode, while image starts with the bytes 0x0000000C 4A584C20 0D0A870A can be decoded normally.

So maybe there is an issue in codestream?

inflation commented 11 months ago

Weird. I can't reproduce it locally. Your best bet is to run:

let buffer: &[u8] = /* file */;
jpegxl_sys::JxlSignatureCheck(buffer.as_ptr(), buffer.len())

And see what happens.

Isotr0py commented 11 months ago

I run with:

let buffer = include_bytes!("./2021-08_wwwwwwww.jxl");

let sign = unsafe { JxlSignatureCheck(buffer.as_ptr(), buffer.len()) };
println!("Signature: {:?}", sign);

let sign = check_valid_signature(buffer);
println!("Signature: {:?}", sign);

let decoder = decoder_builder().build().unwrap();
assert!(matches!(
    decoder.decode(buffer),
    Err(DecodeError::InvalidInput)
));

And it outputs these then passes the assert:

Signature: Codestream
Signature: Some(true)

It's strange because the signature check has passed but the decoding still panicked at DecodeError::InvalidInput.

inflation commented 11 months ago

Huh, then it beyonds me. Try clean the cache and update to the latest version (just published).

Also try using a debugger and see what actually happened if you could. The breakpoint should be decode_internal. https://github.com/inflation/jpegxl-rs/blob/59a7cf17b18deba5cded4712f1655c21c5cce618/jpegxl-rs/src/decode.rs#L202

I also included this sample in the CI and it passed so definitely something weird happened.

Isotr0py commented 11 months ago

OK, clean the cache and update to the latest version did work to me!

Thank you so much for the update and instructions!