jpegxl-rs
jpegxl-rs copied to clipboard
enc_ans.cc:228: JXL_DASSERT: n <= 255
Hello, I got the following failure:
cargo test
running 1 test
./lib/jxl/enc_ans.cc:228: JXL_DASSERT: n <= 255
error: test failed, to rerun pass `--bin reprojxl`
with the following repro project:
Cargo.toml
[package]
name = "reprojxl"
version = "0.1.0"
edition = "2021"
[dependencies]
jpegxl-sys = { version = "=0.11.1" }
jpegxl-rs = { version = "=0.11.1", features = ["vendored"] }
main.rs
fn main() {}
#[test]
fn encode() {
let width = 1;
let height = 1;
let pixels: &[u16] = &[1020u16];
let mut encoder_builder = jpegxl_rs::encoder_builder();
encoder_builder.has_alpha(false);
encoder_builder.lossless(true);
encoder_builder.uses_original_profile(true);
encoder_builder.color_encoding(jpegxl_rs::encode::ColorEncoding::SrgbLuma);
encoder_builder.speed(jpegxl_rs::encode::EncoderSpeed::Kitten);
encoder_builder
.build()
.unwrap()
.encode_frame::<u16, u16>(
&jpegxl_rs::encode::EncoderFrame::new(pixels)
.num_channels(1)
.endianness(jpegxl_rs::Endianness::Native)
.align(0),
width,
height,
)
.unwrap();
}
I was not able to reproduce with a CMake-built libjxl:
git clone -b v0.11.0 --depth 1 https://github.com/libjxl/libjxl.git
cd libjxl
./deps.sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
build/tools/cjxl 1x1_u16.png 1x1_u16.jxl -e 8
# Works fine but maybe PNG is not read as 16-bit monochrome
This is why I am filing an issue here.
Found the culprit, setting the speed (or effort in libjxl term) beyond 7 and also lossless cause this problem, can be reproduced directly using jpegxl-sys or C examples. I guess that they enabled some optimizations beyond that threshold.
use jpegxl_sys::{common::types::*, encoder::encode::*};
#[test]
fn encode() {
unsafe {
let width = 1;
let height = 1;
let pixels: &[u16] = &[1020u16];
let encoder = JxlEncoderCreate(ptr::null_mut());
let pixel_format = JxlPixelFormat {
num_channels: 1,
data_type: JxlDataType::Uint16,
endianness: Endianness::Native,
align: 0,
};
let mut basic_info = {
let mut basic_info = MaybeUninit::uninit();
JxlEncoderInitBasicInfo(basic_info.as_mut_ptr());
basic_info.assume_init()
};
basic_info.xsize = width;
basic_info.ysize = height;
basic_info.bits_per_sample = 16;
basic_info.exponent_bits_per_sample = 0;
basic_info.uses_original_profile = JxlBool::True;
basic_info.num_color_channels = 1;
check(JxlEncoderSetBasicInfo(
encoder,
&basic_info,
));
let mut color_encoding = MaybeUninit::uninit();
JxlColorEncodingSetToSRGB(color_encoding.as_mut_ptr(), true);
check(JxlEncoderSetColorEncoding(
encoder,
color_encoding.as_ptr(),
));
let frame_settings = JxlEncoderFrameSettingsCreate(encoder, ptr::null());
check(JxlEncoderFrameSettingsSetOption(frame_settings, JxlEncoderFrameSettingId::Effort, 8));
check(JxlEncoderSetFrameLossless(frame_settings, true));
check(JxlEncoderAddImageFrame(
frame_settings,
&pixel_format,
pixels.as_ptr().cast(),
pixels.len() * 2,
));
JxlEncoderCloseInput(encoder);
let mut buffer = vec![0; 64];
let mut next_out = buffer.as_mut_ptr();
let mut avail_out = buffer.len();
loop {
let status = JxlEncoderProcessOutput(
encoder,
&mut next_out,
&mut avail_out,
);
if status == JxlEncoderStatus::NeedMoreOutput {
let offset = next_out.offset_from(buffer.as_mut_ptr());
buffer.resize(buffer.len() * 2, 0);
next_out = buffer.as_mut_ptr().add(offset.unsigned_abs());
avail_out = buffer.len() - offset.unsigned_abs();
} else {
check(status);
break;
}
}
println!("Output: {buffer:?}");
}
}
#[track_caller]
fn check(status: JxlEncoderStatus) {
let JxlEncoderStatus::Success = status else {
panic!("Error: {status:?}")
};
}