Yalantis/uCrop · error · CImgArgumentException
save_jxl(): bytes_per_pixel must be in [0, 2] and less than…
Error message
save_jxl(): bytes_per_pixel must be in [0, 2] and less than or equal to sizeof(T)
What it means
save_jxl() accepts bytes_per_pixel of 0 (auto), 1 (8-bit), or 2 (16-bit), and it must not exceed sizeof(T) of the image's pixel type. Otherwise CImg throws CImgArgumentException, because the requested output bit depth cannot be represented from the underlying storage type.
Solutions
- Pass bytes_per_pixel within [0,2] and <= sizeof(T): use 0 (auto) unless you specifically need 8/16-bit output.
- If you need 16-bit JXL from byte data, first convert the image: CImg<unsigned short> out = img * 257; then save with bytes_per_pixel=2.
- Clamp the parameter at the call site based on the image type.
Example fix
// before
CImg<unsigned char> img(...);
img.save_jxl("out.jxl", 1.0f, 2); // sizeof(T)=1 < 2 -> throw
// after
CImg<unsigned short> out = img * 257;
out.save_jxl("out.jxl", 1.0f, 2); Defensive patterns
Strategy: validation
Validate before calling
if (bytesPerPixel > 2 || sizeof(T) < bytesPerPixel) {
throw std::invalid_argument("bytes_per_pixel must be in [0,2] and <= sizeof(T)");
}
img.save_jxl("out.jxl", 1.0f, bytesPerPixel); Prevention
- Default to bytes_per_pixel=0 (auto) unless bit depth matters.
- Compute bpp from the image type, never hardcode.
- Convert pixel type first if 16-bit JXL output is required.
When it happens
Trigger: Calling img.save_jxl(path, distance, bpp) with bpp==3 or higher, or with bpp larger than sizeof(T) — e.g. bytes_per_pixel==2 on a CImg<char>/CImg<unsigned char> (sizeof(T)==1).
Common situations: Copy-pasted save calls where the bpp parameter was tuned for float images (sizeof 4) then reused on byte images, or hardcoded 16-bit output requested on 8-bit data.
Related errors
- save_jxl(): JPEG XL only supports at most 4 channels.
- cimg::dialog(): No buttons have been defined.
- load_ascii(): Invalid ascii header in file
- load_jxl(): Does not support animated JPEG XL
- load_jxl(): Failed to configure decoder
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/274212c189abc0d6.
Report an issue: GitHub.
Appendix: source
Thrown at ucrop/src/main/jni/CImg.h:61780
const CImg<T>& _save_jxl(const char *const filename, const float distance=1.0f,
const unsigned int bytes_per_pixel=0) const {
if (!filename)
throw CImgArgumentException(_cimg_instance
"save_jxl(): Specified filename is (null).",
cimg_instance);
if (_spectrum > 4)
throw CImgArgumentException(_cimg_instance
"save_jxl(): JPEG XL only supports at most 4 channels.",
cimg_instance);
double stmin, stmax = (double)max_min(stmin);
if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
cimg::warn(_cimg_instance
"save_jxl(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.",
cimg_instance,
stmin,stmax,filename);
if (bytes_per_pixel>2 || sizeof(T)<bytes_per_pixel)
throw CImgArgumentException(_cimg_instance
"save_jxl(): bytes_per_pixel must be in [0, 2] and less than or equal to sizeof(T)",
cimg_instance);
if (_depth>1)
cimg::warn(_cimg_instance
"save_jxl(): Instance is volumetric, only the first slice will be saved in file '%s'.",
cimg_instance,
filename);
#ifndef cimg_use_jxl
cimg::unused(distance);
return save_other(filename);
#else
std::FILE *file = cimg::fopen(filename, "wb");
cimg_uint32 nChannels = _spectrum;
bool hasAlpha = _spectrum==2 || _spectrum==4;
if (hasAlpha) --nChannels;
unsigned int bytesPerPixel = bytes_per_pixel;
if (bytesPerPixel==0)
bytesPerPixel = stmax<256?1:2;View on GitHub (pinned to f788b534b4)