Yalantis/uCrop · error · CImgInstanceException
XYZtoRGB(): Instance is not a XYZ image.
Error message
XYZtoRGB(): Instance is not a XYZ image.
What it means
XYZtoRGB() converts CIE XYZ values back to RGB in place and requires exactly 3 channels (_spectrum==3); the same spectrum check as the other conversions triggers this exception when it fails. It reads and writes the three channel planes directly.
Solutions
- Guard with if (img.spectrum()==3) before the call.
- Reduce 4-channel XYZ buffers with channels(0,2).
- Expand 1-channel luminance buffers with get_append before conversion.
- Catch CImgInstanceException and log img.spectrum() for diagnosis.
Example fix
// before CImg<float> xyz = loadXYZ(); // may include alpha xyz.XYZtoRGB(); // after CImg<float> xyz = loadXYZ(); if (xyz.spectrum()==4) xyz.channels(0,2); assert(xyz.spectrum()==3); xyz.XYZtoRGB();
Defensive patterns
Strategy: validation
Validate before calling
if (img.spectrum()==4) img.channels(0,2);
if (img.spectrum()!=3) throw std::runtime_error("XYZ image must have 3 channels"); Type guard
bool isXYZ(const cimg_library::CImg<T>& img) { return img.spectrum()==3; } Try / catch
try {
img.XYZtoRGB();
} catch (const cimg_library::CImgInstanceException& e) {
std::cerr << "XYZtoRGB needs 3 channels; got " << img.spectrum() << std::endl;
} Prevention
- Keep XYZ intermediates at exactly 3 channels (no alpha)
- Check spectrum() before the reverse conversion in round-trip code
- Validate channel count after any intermediate serialization/deserialization
When it happens
Trigger: Calling img.XYZtoRGB() on grayscale, RGBA, or empty images, or on XYZ buffers produced with a different channel layout.
Common situations: Color pipelines where XYZ intermediates were stored with extra channels (e.g.XYZA); grayscale XYZ luminance-only buffers; round-trip code skipping the spectrum check.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- RGBtoXYZ(): Instance is not a RGB image.
- CMYKtoCMY(): Instance is not a CMYK image.
- CMYtoCMYK(): Instance is not a CMY image.
- CMYtoRGB(): Instance is not a CMY image.
- RGBtoCMY(): Instance is not a RGB image.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/cb5421987d02e5c8.
Report an issue: GitHub.
Appendix: source
Thrown at ucrop/src/main/jni/CImg.h:37568
p2[N] = (T)(0.22248840*R + 0.71690369*G + 0.06060791*B);
p3[N] = (T)(0.01391602*R + 0.09706116*G + 0.71392822*B);
}
}
return *this;
}
//! Convert pixel values from RGB to XYZ color spaces \newinstance.
CImg<Tfloat> get_RGBtoXYZ(const bool use_D65=true) const {
return CImg<Tfloat>(*this,false).RGBtoXYZ(use_D65);
}
//! Convert pixel values from XYZ to RGB color spaces.
/**
\param use_D65 Tell to use the D65 illuminant (D50 otherwise).
**/
CImg<T>& XYZtoRGB(const bool use_D65=true) {
if (_spectrum!=3)
throw CImgInstanceException(_cimg_instance
"XYZtoRGB(): Instance is not a XYZ image.",
cimg_instance);
T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
const longT whd = (longT)width()*height()*depth();
cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,2048))
for (longT N = 0; N<whd; ++N) {
const Tfloat
X = (Tfloat)p1[N]*255,
Y = (Tfloat)p2[N]*255,
Z = (Tfloat)p3[N]*255;
if (use_D65) {
p1[N] = (T)cimg::cut(3.2404542*X - 1.5371385*Y - 0.4985314*Z,0,255);
p2[N] = (T)cimg::cut(-0.9692660*X + 1.8760108*Y + 0.0415560*Z,0,255);
p3[N] = (T)cimg::cut(0.0556434*X - 0.2040259*Y + 1.0572252*Z,0,255);
} else {
p1[N] = (T)cimg::cut(3.134274799724*X - 1.617275708956*Y - 0.490724283042*Z,0,255);
p2[N] = (T)cimg::cut(-0.978795575994*X + 1.916161689117*Y + 0.033453331711*Z,0,255);View on GitHub (pinned to f788b534b4)