Yalantis/uCrop · error · CImgInstanceException
HSItoRGB(): Instance is not a HSI image.
Error message
HSItoRGB(): Instance is not a HSI image.
What it means
CImg<T>::HSItoRGB() converts HSI pixel values back to RGB and requires the image to have exactly 3 channels (H, S and I planes). With any other spectrum the conversion is undefined, so it throws CImgInstanceException. Like its RGB counterpart, it validates channel count only, not that the values are genuinely in HSI form.
Source
Thrown at ucrop/src/main/jni/CImg.h:37102
H = 60*(C==0?0:M==R?cimg::mod((G - B)/C,(Tfloat)6):M==G?(B - R)/C + 2:(R - G)/C + 4),
S = sum<=0?0:1 - 3*m/sum,
I = sum/(3*255);
p1[N] = (T)H;
p2[N] = (T)S;
p3[N] = (T)I;
}
return *this;
}
//! Convert pixel values from RGB to HSI color spaces \newinstance.
CImg<Tfloat> get_RGBtoHSI() const {
return CImg<Tfloat>(*this,false).RGBtoHSI();
}
//! Convert pixel values from HSI to RGB color spaces.
CImg<T>& HSItoRGB() {
if (_spectrum!=3)
throw CImgInstanceException(_cimg_instance
"HSItoRGB(): Instance is not a HSI 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],
I = (Tfloat)p3[N],
Z = 1 - cimg::abs(cimg::mod(H,(Tfloat)2) - 1),
C = I*S/(1 + Z),
X = C*Z,
m = I*(1 - S)/3;
Tfloat R, G, B;
switch ((int)H) {
case 0 : R = C; G = X; B = 0; break;View on GitHub (pinned to f788b534b4)
Solutions
- Ensure spectrum()==3 before calling; for grayscale, replicate the channel to 3 and set S=0, I=value (or just skip conversion since it's already intensity-like).
- Strip alpha (channels(0,2)) before the conversion.
- Check for intermediate save/load steps that change channel count between RGBtoHSI and HSItoRGB.
- Wrap round trips in a sanity assert: assert(hsi.spectrum()==3).
Example fix
// before CImg<float> gray = hsi.get_channel(0); // someone extracted one channel gray.HSItoRGB(); // throws // after CImg<float> rgb = hsi; // keep all 3 channels rgb.HSItoRGB();
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.HSItoRGB(); Type guard
template<typename T> bool isHsiShape(const CImg<T>& img) { return img.spectrum() == 3; } Try / catch
try {
img.HSItoRGB();
} catch (const CImgInstanceException& e) {
std::fprintf(stderr, "HSItoRGB requires 3 channels, image has %d\n", img.spectrum());
} Prevention
- Keep forward/inverse conversions in the same scope with no intermediate save/load.
- Assert spectrum()==3 between RGBtoHSI and HSItoRGB.
- Strip alpha channels before conversions.
- Skip the conversion entirely for grayscale data instead of forcing channels.
When it happens
Trigger: Calling img.HSItoRGB() on a grayscale (spectrum=1) or RGBA (spectrum=4) image; losing channels between RGBtoHSI() and HSItoRGB() (e.g. saving/loading in between, or channels(0,1) extraction).
Common situations: Round-trip pipelines where a save to a grayscale format silently drops to 1 channel before the inverse conversion; alpha-channel images; applying HSItoRGB to a raw 1-channel buffer.
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.
- RGBtoHSL(): Instance is not a RGB image.
- HSLtoRGB(): Instance is not a HSL 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/c5d35f5166799f5d.
Report an issue: GitHub.