Yalantis/uCrop · error · CImgInstanceException

CMYtoRGB(): Instance is not a CMY image.

Error message

CMYtoRGB(): Instance is not a CMY image.

What it means

CMYtoRGB() converts CMY channels back to RGB in place and requires exactly 3 channels; the same _spectrum!=3 check triggers the exception. The message 'not a CMY image' reflects the expected source color space, but the check is purely channel-count based.

Source

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

          C = 255 - R,
          M = 255 - G,
          Y = 255 - B;
        p1[N] = (T)cimg::cut(C,0,255),
        p2[N] = (T)cimg::cut(M,0,255),
        p3[N] = (T)cimg::cut(Y,0,255);
      }
      return *this;
    }

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

    //! Convert pixel values from CMY to RGB color spaces.
    CImg<T>& CMYtoRGB() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "CMYtoRGB(): Instance is not a CMY 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,2048))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          C = (Tfloat)p1[N],
          M = (Tfloat)p2[N],
          Y = (Tfloat)p3[N],
          R = 255 - C,
          G = 255 - M,
          B = 255 - Y;
        p1[N] = (T)cimg::cut(R,0,255),
        p2[N] = (T)cimg::cut(G,0,255),
        p3[N] = (T)cimg::cut(B,0,255);
      }

View on GitHub (pinned to f788b534b4)

Solutions

  1. Check spectrum()==3 before calling.
  2. If the image is CMYK (4 channels), call CMYKtoCMY() first, then CMYtoRGB().
  3. Expand grayscale to 3 channels with get_append before treating as CMY.
  4. Catch CImgInstanceException and log the actual spectrum.

Example fix

// before
CImg<float> img = loadCMYK(); // spectrum 4
img.CMYtoRGB();
// after
CImg<float> img = loadCMYK();
if (img.spectrum()==4) img.CMYKtoCMY().CMYtoRGB();
else if (img.spectrum()==3) img.CMYtoRGB();
Defensive patterns

Strategy: validation

Validate before calling

if (img.spectrum()==4) img.CMYKtoCMY();
if (img.spectrum()!=3) throw std::runtime_error("CMY image with 3 channels required");

Type guard

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

Try / catch

try {
  img.CMYtoRGB();
} catch (const cimg_library::CImgInstanceException& e) {
  std::cerr << "CMY required; spectrum=" << img.spectrum() << std::endl;
}

Prevention

When it happens

Trigger: Calling img.CMYtoRGB() on grayscale, RGBA, 4-channel CMYK, or empty images.

Common situations: Print workflows where a 4-channel CMYK buffer is passed directly instead of being reduced to CMY; RGB images converted twice; images loaded with unexpected channel counts.

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