Yalantis/uCrop · error · CImgInstanceException
RGBtoXYZ(): Instance is not a RGB image.
Error message
RGBtoXYZ(): Instance is not a RGB image.
What it means
RGBtoXYZ() converts pixel values from sRGB to the CIE XYZ color space in place (D65 by default) and requires exactly 3 channels. CImg throws CImgInstanceException when _spectrum!=3 because the transform operates directly on the three channel planes.
Solutions
- Guard with if (img.spectrum()==3) before the call.
- Expand grayscale: img.get_append(img,img,'c').
- Reduce 4-channel images with channels(0,2) or select bands explicitly.
- Catch CImgInstanceException to handle non-RGB input.
Example fix
// before CImg<float> img = loadMultispectral(); // spectrum>3 img.RGBtoXYZ(); // after CImg<float> img = loadMultispectral(); if (img.spectrum()==3) img.RGBtoXYZ(); else CImg<float> rgb = img.get_channels(0,2).RGBtoXYZ();
Defensive patterns
Strategy: validation
Validate before calling
if (img.spectrum()!=3) {
if (img.spectrum()==1) img.append(img,img,img,'c');
else if (img.spectrum()>3) img.channels(0,2);
}
if (img.spectrum()!=3) throw std::runtime_error("RGB required for XYZ conversion"); Type guard
bool isRGB(const cimg_library::CImg<T>& img) { return img.spectrum()==3; } Try / catch
try {
img.RGBtoXYZ();
} catch (const cimg_library::CImgInstanceException& e) {
std::cerr << "RGBtoXYZ needs 3 channels; got " << img.spectrum() << std::endl;
} Prevention
- For multispectral data select exactly 3 bands before color conversion
- Check spectrum() after loading, since file format determines channel count
- Normalize to RGB once at pipeline entry, not at each conversion site
When it happens
Trigger: Calling img.RGBtoXYZ() (or RGBtoLab/RGBtoHSL chains built on it) on grayscale, RGBA, or empty images.
Common situations: Color-management code paths fed grayscale or alpha-bearing images; scientific imaging with multi-band (spectrum>3) data; un-initialized CImg buffers.
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
- XYZtoRGB(): Instance is not a XYZ 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/bef6249e087a8ddd.
Report an issue: GitHub.
Appendix: source
Thrown at ucrop/src/main/jni/CImg.h:37532
K = (Tfloat)ps4[N],
K1 = 1 - K/255,
nC = C*K1 + K,
nM = M*K1 + K,
nY = Y*K1 + K;
pd1[N] = (Tfloat)cimg::cut(nC,0,255),
pd2[N] = (Tfloat)cimg::cut(nM,0,255),
pd3[N] = (Tfloat)cimg::cut(nY,0,255);
}
return res;
}
//! Convert pixel values from RGB to XYZ color spaces.
/**
\param use_D65 Tell to use the D65 illuminant (D50 otherwise).
**/
CImg<T>& RGBtoXYZ(const bool use_D65=true) {
if (_spectrum!=3)
throw CImgInstanceException(_cimg_instance
"RGBtoXYZ(): Instance is not a RGB 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
R = (Tfloat)p1[N]/255,
G = (Tfloat)p2[N]/255,
B = (Tfloat)p3[N]/255;
if (use_D65) { // D65
p1[N] = (T)(0.4124564*R + 0.3575761*G + 0.1804375*B);
p2[N] = (T)(0.2126729*R + 0.7151522*G + 0.0721750*B);
p3[N] = (T)(0.0193339*R + 0.1191920*G + 0.9503041*B);
} else { // D50
p1[N] = (T)(0.43603516*R + 0.38511658*G + 0.14305115*B);
p2[N] = (T)(0.22248840*R + 0.71690369*G + 0.06060791*B);View on GitHub (pinned to f788b534b4)