Yalantis/uCrop · error · CImgInstanceException

YCbCrtoRGB(): Instance is not a YCbCr image.

Error message

YCbCrtoRGB(): Instance is not a YCbCr image.

What it means

YCbCrtoRGB() converts channels back from YCbCr to RGB in place and, like all channel-wise color conversions in CImg, requires exactly 3 channels (_spectrum==3). The exception fires when the image is grayscale, RGBA, or empty. It exists because the kernel reads three channel planes directly.

Source

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

          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);
      }
      return *this;
    }

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

    //! Convert pixel values from RGB to YCbCr color spaces.
    CImg<T>& YCbCrtoRGB() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "YCbCrtoRGB(): Instance is not a YCbCr 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
          Y = (Tfloat)p1[N] - 16,
          Cb = (Tfloat)p2[N] - 128,
          Cr = (Tfloat)p3[N] - 128,
          R = (298*Y + 409*Cr + 128)/256,
          G = (298*Y - 100*Cb - 208*Cr + 128)/256,
          B = (298*Y + 516*Cb + 128)/256;
        p1[N] = (T)cimg::cut(R,(Tfloat)0,(Tfloat)255),
        p2[N] = (T)cimg::cut(G,(Tfloat)0,(Tfloat)255),
        p3[N] = (T)cimg::cut(B,(Tfloat)0,(Tfloat)255);
      }

View on GitHub (pinned to f788b534b4)

Solutions

  1. Check spectrum()==3 first; if 1, replicate the gray channel into 3; if 4, reduce with channels(0,2).
  2. Ensure the image was previously converted to YCbCr on a 3-channel copy.
  3. Construct/assign images with explicit spectrum=3 when color is expected.
  4. Catch CImgInstanceException and report which channel count was found.

Example fix

// before
CImg<unsigned char> img("input.png");
img.YCbCrtoRGB(); // throws if not 3 channels
// after
CImg<unsigned char> img("input.png");
if (img.spectrum()!=3) throw std::runtime_error("expected RGB image");
img.YCbCrtoRGB();
Defensive patterns

Strategy: validation

Validate before calling

if (img.spectrum()!=3) throw std::runtime_error("YCbCrtoRGB requires 3-channel image");

Type guard

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

Try / catch

try {
  img.YCbCrtoRGB();
} catch (const cimg_library::CImgInstanceException& e) {
  // normalize and retry once
  if (img.spectrum()==1) img.append(img,img,img,'c').YCbCrtoRGB();
}

Prevention

When it happens

Trigger: Calling img.YCbCrtoRGB() on any CImg whose spectrum() != 3, e.g. after loading a grayscale or alpha-channel image, or on an unassigned CImg.

Common situations: Round-trip pipelines where an intermediate step dropped or added channels; loading user-supplied images of varying channel counts; 4-channel (CMYK/RGBA) buffers mistakenly fed to YCbCr conversion.

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