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
- Check spectrum()==3 first; if 1, replicate the gray channel into 3; if 4, reduce with channels(0,2).
- Ensure the image was previously converted to YCbCr on a 3-channel copy.
- Construct/assign images with explicit spectrum=3 when color is expected.
- 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
- Only call YCbCrtoRGB on images that passed through RGBtoYCbCr on a 3-channel image
- Assert spectrum()==3 at pipeline stage boundaries
- Avoid channel-count-reducing operations (e.g. mean over channels) mid-pipeline
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
- RGBtoYCbCr(): Instance is not a RGB image.
- RGBtoYUV(): Instance is not a RGB image.
- YUVtoRGB(): Instance is not a YUV image.
- RGBtoCMY(): Instance is not a RGB image.
- CMYtoRGB(): Instance is not a CMY image.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/d9c0d707d80a8e2a.
Report an issue: GitHub.