Yalantis/uCrop · error · CImgInstanceException
XYZtoxyY(): Instance is not a XYZ image.
Error message
XYZtoxyY(): Instance is not a XYZ image.
What it means
XYZtoxyY() converts CIE XYZ channels to xyY chromaticity coordinates and requires exactly 3 channels (X, Y, Z). It throws CImgInstanceException when _spectrum != 3 because it operates on the three channel planes directly. Like the other color conversions, it is a precondition on the whole image instance.
Source
Thrown at ucrop/src/main/jni/CImg.h:37666
X = (Tfloat)(24389*cX>216?cX*cX*cX:(116*cX - 16)*27/24389),
Y = (Tfloat)(27*L>216?cY*cY*cY:27*L/24389),
Z = (Tfloat)(24389*cZ>216?cZ*cZ*cZ:(116*cZ - 16)*27/24389);
p1[N] = (T)(X*white[0]);
p2[N] = (T)(Y*white[1]);
p3[N] = (T)(Z*white[2]);
}
return *this;
}
//! Convert pixel values from Lab to XYZ color spaces \newinstance.
CImg<Tfloat> get_LabtoXYZ(const bool use_D65=true) const {
return CImg<Tfloat>(*this,false).LabtoXYZ(use_D65);
}
//! Convert pixel values from XYZ to xyY color spaces.
CImg<T>& XYZtoxyY() {
if (_spectrum!=3)
throw CImgInstanceException(_cimg_instance
"XYZtoxyY(): Instance is not a XYZ 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,4096))
for (longT N = 0; N<whd; ++N) {
const Tfloat
X = (Tfloat)p1[N],
Y = (Tfloat)p2[N],
Z = (Tfloat)p3[N],
sum = X + Y + Z,
nsum = sum>0?sum:1;
p1[N] = (T)(X/nsum);
p2[N] = (T)(Y/nsum);
p3[N] = (T)Y;
}
return *this;View on GitHub (pinned to f788b534b4)
Solutions
- Assert spectrum()==3 before calling and correct the upstream pipeline (RGB -> RGBtoXYZ -> XYZtoxyY).
- If the image is RGB, convert with RGBtoXYZ() first so the channels genuinely hold XYZ.
- If the image has 1 or 4+ channels, project to 3 channels (get_channels(0,2) for RGBA) or rebuild the image as 3-channel before converting.
- Catch CImgInstanceException around the call in native/JNI layers.
Example fix
// before frame.XYZtoxyY(); // frame is RGBA, spectrum==4 -> throws // after CImg<float> xyz = frame.get_channels(0,2).RGBtoXYZ(); // ensure real XYZ, 3 channels CImg<float> xyy = xyz.get_XYZtoxyY();
Defensive patterns
Strategy: validation
Validate before calling
if (img.spectrum()!=3) { /* repair before XYZtoxyY */ } Type guard
template<class T> bool has3Channels(const cimg_library::CImg<T>& i){ return i.spectrum()==3; } Try / catch
try { img.XYZtoxyY(); } catch (cimg_library::CImgInstanceException& e) { /* fallback */ } Prevention
- Run RGBtoXYZ before XYZtoxyY when starting from RGB
- Validate channels at pipeline entry
When it happens
Trigger: Calling img.XYZtoxyY() (or get_XYZtoxyY()) on any image whose spectrum is not 3: grayscale (_spectrum==1), RGB without XYZ conversion, RGBA (_spectrum==4), or video/sequence data with more channels.
Common situations: Chaining XYZtoxyY after RGBtoXYZ on an RGBA image where the XYZ conversion was applied to only part of the data; applying the transform to a single-channel luminance map; mis-ordered conversion pipeline on multi-channel scientific imagery.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- XYZtoLab(): Instance is not a XYZ image.
- LabtoXYZ(): Instance is not a Lab image.
- xyYtoXYZ(): Instance is not a xyY image.
- RGBtoYCbCr(): Instance is not a RGB image.
- YCbCrtoRGB(): Instance is not a YCbCr image.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/18da5c4799e2b7bf.
Report an issue: GitHub.