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

  1. Guard with if (img.spectrum()==3) before the call.
  2. Expand grayscale: img.get_append(img,img,'c').
  3. Reduce 4-channel images with channels(0,2) or select bands explicitly.
  4. 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

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


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)