Yalantis/uCrop · error · CImgInstanceException
HSLtoRGB(): Instance is not a HSL image.
Error message
HSLtoRGB(): Instance is not a HSL image.
What it means
CImg<T>::HSLtoRGB() converts HSL values back to RGB and requires exactly 3 channels (H, S, L planes). Any other spectrum throws CImgInstanceException. It validates only the channel count, not that the stored values actually represent HSL.
Source
Thrown at ucrop/src/main/jni/CImg.h:37175
H = 60*(C==0?0:M==R?cimg::mod((G - B)/C,(Tfloat)6):M==G?(B - R)/C + 2:(R - G)/C + 4),
L = 0.5f*(m + M)/255,
S = L==1 || L==0?0:C/(1 - cimg::abs(2*L - 1))/255;
p1[N] = (T)H;
p2[N] = (T)S;
p3[N] = (T)L;
}
return *this;
}
//! Convert pixel values from RGB to HSL color spaces \newinstance.
CImg<Tfloat> get_RGBtoHSL() const {
return CImg<Tfloat>(*this,false).RGBtoHSL();
}
//! Convert pixel values from HSL to RGB color spaces.
CImg<T>& HSLtoRGB() {
if (_spectrum!=3)
throw CImgInstanceException(_cimg_instance
"HSLtoRGB(): Instance is not a HSL 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,256))
for (longT N = 0; N<whd; ++N) {
const Tfloat
H = cimg::mod((Tfloat)p1[N]/60,(Tfloat)6),
S = (Tfloat)p2[N],
L = (Tfloat)p3[N],
C = (1 - cimg::abs(2*L - 1))*S,
X = C*(1 - cimg::abs(cimg::mod(H,(Tfloat)2) - 1)),
m = L - C/2;
Tfloat R, G, B;
switch ((int)H) {
case 0 : R = C; G = X; B = 0; break;
case 1 : R = X; G = C; B = 0; break;View on GitHub (pinned to f788b534b4)
Solutions
- Ensure spectrum()==3 (replicate or drop channels as needed) before calling.
- Strip alpha via channels(0,2) if present.
- Verify round-trip integrity: assert(img.spectrum()==3) after RGBtoHSL and before HSLtoRGB.
- Avoid intermediate format conversions that alter channel count mid-pipeline.
Example fix
// before
CImg<float> hsl("hsl.png"); // saved as 4-channel RGBA
hsl.HSLtoRGB(); // throws
// after
CImg<float> hsl("hsl.png");
if (hsl.spectrum() == 4) hsl.channels(0,2);
hsl.HSLtoRGB(); Defensive patterns
Strategy: type-guard
Validate before calling
template<typename T> bool is3Channel(const CImg<T>& img) { return img.spectrum() == 3; }
if (is3Channel(img)) img.HSLtoRGB(); Type guard
template<typename T> bool isHslShape(const CImg<T>& img) { return img.spectrum() == 3; } Try / catch
try {
img.HSLtoRGB();
} catch (const CImgInstanceException& e) {
std::fprintf(stderr, "HSLtoRGB requires 3 channels, image has %d\n", img.spectrum());
} Prevention
- Assert spectrum()==3 between RGBtoHSL and HSLtoRGB.
- Avoid intermediate grayscale saves in HSL round trips.
- Strip alpha before conversion.
- Check spectrum after every loading or resizing operation.
When it happens
Trigger: Calling img.HSLtoRGB() on grayscale (spectrum=1) or RGBA (spectrum=4) images, or after channel-count changes between RGBtoHSL() and HSLtoRGB().
Common situations: Round-trip interrupted by a grayscale save/load; alpha handling code that left 4 channels; applying the inverse conversion to single-channel luminance data.
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
- RGBtoHSI(): Instance is not a RGB image.
- HSItoRGB(): Instance is not a HSI image.
- RGBtoHSL(): Instance is not a RGB image.
- RGBtoHSV(): Instance is not a RGB image.
- HSVtoRGB(): Instance is not a HSV image.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/5bfd392657feaf57.
Report an issue: GitHub.