Yalantis/uCrop · error · CImgInstanceException

RGBtoYCbCr(): Instance is not a RGB image.

Error message

RGBtoYCbCr(): Instance is not a RGB image.

What it means

CImg's RGBtoYCbCr() converts pixel channels in place from RGB to YCbCr and only works on 3-channel images. The library throws CImgInstanceException when _spectrum!=3 because the per-channel pointer arithmetic (data(0,0,0,0..2)) assumes exactly R, G, B planes. It is a precondition check guarding in-place channel-wise transforms.

Source

Thrown at ucrop/src/main/jni/CImg.h:37284

        case 4 : R = X; G = 0; B = C; break;
        default : R = C; G = 0; B = X;
        }
        p1[N] = (T)((R + m)*255);
        p2[N] = (T)((G + m)*255);
        p3[N] = (T)((B + m)*255);
      }
      return *this;
    }

    //! Convert pixel values from HSV to RGB color spaces \newinstance.
    CImg<Tuchar> get_HSVtoRGB() const {
      return CImg<Tuchar>(*this,false).HSVtoRGB();
    }

    //! Convert pixel values from RGB to YCbCr color spaces.
    CImg<T>& RGBtoYCbCr() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoYCbCr(): 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,512))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          Y = (66*R + 129*G + 25*B + 128)/256 + 16,
          Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
          Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
        p1[N] = (T)cimg::cut(Y,(Tfloat)0,(Tfloat)255),
        p2[N] = (T)cimg::cut(Cb,(Tfloat)0,(Tfloat)255),
        p3[N] = (T)cimg::cut(Cr,(Tfloat)0,(Tfloat)255);
      }

View on GitHub (pinned to f788b534b4)

Solutions

  1. Verify img.spectrum()==3 before calling; convert first, e.g. if (img.spectrum()==1) img.append(img,img,img,'c');
  2. For RGBA images drop the alpha channel: img.channels(0,2) then call RGBtoYCbCr().
  3. Ensure the image was actually loaded/assigned (an empty CImg has spectrum 0).
  4. Wrap the call in try/catch for CImgInstanceException to surface a clear message.

Example fix

// before
CImg<unsigned char> img("photo.png"); // may be grayscale or RGBA
img.RGBtoYCbCr(); // throws if spectrum!=3
// after
CImg<unsigned char> img("photo.png");
if (img.spectrum()==1) img.append(img,img,img,'c');
else if (img.spectrum()==4) img.channels(0,2);
img.RGBtoYCbCr();
Defensive patterns

Strategy: validation

Validate before calling

if (img.width()==0 || img.spectrum()!=3) {
  if (img.spectrum()==1) img.append(img,img,img,'c');
  else if (img.spectrum()==4) img.channels(0,2);
  else throw std::runtime_error("RGB image with 3 channels required");
}

Type guard

bool isRGB(const cimg_library::CImg<T>& img) { return img.spectrum()==3 && img.size()>0; }

Try / catch

try {
  img.RGBtoYCbCr();
} catch (const cimg_library::CImgInstanceException& e) {
  std::cerr << "Need 3-channel image, got spectrum=" << img.spectrum() << std::endl;
}

Prevention

When it happens

Trigger: Calling img.RGBtoYCbCr() on an image whose spectrum() is not 3 — e.g. grayscale (1 channel), RGBA (4 channels), or an empty/default-constructed CImg.

Common situations: Loading a grayscale PNG/JPEG or a PNG with alpha and passing it straight into a color-conversion pipeline; creating a CImg via constructor without specifying spectrum=3; channel slices or channel appended results with wrong count.

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/2a49231a9f89b1b3. Report an issue: GitHub.