Yalantis/uCrop · error · CImgIOException
save_jxl(): Failed to set lossy compression level when savin
Error message
save_jxl(): Failed to set lossy compression level when saving file '%s'.
What it means
For lossy JXL, CImg sets the compression distance via JxlEncoderSetFrameDistance. A non-success return makes save_jxl() tear down the encoder and throw CImgIOException, meaning libjxl rejected the requested distance value (e.g. out of its accepted range) or the encoder is in a bad state.
Source
Thrown at ucrop/src/main/jni/CImg.h:61887
}
JxlColorEncoding colorEncoding = {};
JXL_BOOL isGray = pixelFormat.num_channels<3?JXL_TRUE:JXL_FALSE;
JxlColorEncodingSetToSRGB(&colorEncoding, isGray);
if (JXL_ENC_SUCCESS!=JxlEncoderSetColorEncoding(encoder,&colorEncoding)) {
cimg::fclose(file);
JxlEncoderDestroy(encoder);
throw CImgIOException(_cimg_instance
"save_jxl(): Failed to set color encoding when saving file '%s'.",
cimg_instance,
filename);
}
JxlEncoderFrameSettings* frameSettings = JxlEncoderFrameSettingsCreate(encoder,NULL);
if (JXL_ENC_SUCCESS!=JxlEncoderSetFrameDistance(frameSettings,distance)) {
cimg::fclose(file);
JxlEncoderDestroy(encoder);
throw CImgIOException(_cimg_instance
"save_jxl(): Failed to set lossy compression level when saving file '%s'.",
cimg_instance,
filename);
}
if (JXL_ENC_SUCCESS!=JxlEncoderAddImageFrame(frameSettings,&pixelFormat,(const void*)rgbBuffer._data,
rgbBuffer.size())) {
cimg::fclose(file);
JxlEncoderDestroy(encoder);
throw CImgIOException(_cimg_instance
"save_jxl(): Failed to set image data when saving file '%s'.",
cimg_instance,
filename);
}
CImg<ucharT> alphaBuffer;
if (hasAlpha) {
ucharT *alphaPtr = (ucharT*)ptr_a;
if (sizeof(T)!=bytesPerPixel) {View on GitHub (pinned to f788b534b4)
Solutions
- Use a valid distance in [0, 25]: 0 for lossless, ~1.0 for visually lossless.
- Convert a JPEG-style quality q to distance, e.g. distance = q >= 100 ? 0 : (100 - q) / 10.0f, before calling save_jxl.
- Clamp/validate the distance parameter at the call site.
Example fix
// before
int quality = 85;
img.save_jxl("out.jxl", (float)quality); // 85 is out of JXL distance range
// after
float distance = quality >= 100 ? 0.0f : (100.0f - quality) / 10.0f;
img.save_jxl("out.jxl", distance); Defensive patterns
Strategy: validation
Validate before calling
float dist = quality >= 100 ? 0.0f : (100.0f - quality) / 10.0f;
if (dist < 0.0f || dist > 25.0f) {
throw std::invalid_argument("jxl distance must be within [0, 25]");
}
img.save_jxl("out.jxl", dist); Prevention
- Never pass JPEG quality (1-100) directly as JXL distance.
- Clamp distance to [0, 25] at call sites.
- Use 0.0 for lossless and ~1.0 for visually lossless defaults.
When it happens
Trigger: Calling save_jxl(path, distance) with a distance value libjxl rejects — JXL distance is typically 0 (lossless) up to ~25; passing a negative value, NaN, or an out-of-range number triggers this.
Common situations: Users porting JPEG quality (1–100) directly into the JXL distance parameter, or config files supplying quality as a 0–100 scale that is passed unconverted to distance.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- load_bmp(): Unable to load compressed data from '(*FILE)' in
- load_jxl(): Failed to get file size '%s'.
- load_jxl(): Failed to configure decoder '%s'.
- load_jxl(): Failed to load image data '%s'.
- load_jxl(): Failed to decode image '%s'.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/e2bb430f74b75000.
Report an issue: GitHub.