Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enc_ans.cc:228: JXL_DASSERT: n <= 255 #101

Open
y-guyon opened this issue Oct 11, 2024 · 1 comment
Open

enc_ans.cc:228: JXL_DASSERT: n <= 255 #101

y-guyon opened this issue Oct 11, 2024 · 1 comment
Labels

Comments

@y-guyon
Copy link

y-guyon commented Oct 11, 2024

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.

@inflation
Copy link
Owner

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:?}")
    };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants