Yalantis/uCrop · error · CImgArgumentException

draw_triangle(): Invalid specified light texture (%u,%u,%u,%

Error message

draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).

What it means

draw_triangle() (2D variant) supports a `light` texture argument used for gouraud/textured shading. If the light image has depth > 1 (it is a volume, not a 2D texture) or fewer channels than the drawing image's spectrum, the texture cannot be sampled per-pixel, so CImg throws CImgArgumentException with the light image's dimensions for diagnosis.

Source

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

       \param opacity Drawing opacity.
    **/
    template<typename tc, typename tl>
    CImg<T>& draw_triangle(int x0, int y0,
                           int x1, int y1,
                           int x2, int y2,
                           const tc *const color,
                           const CImg<tl>& light,
                           int lx0, int ly0,
                           int lx1, int ly1,
                           int lx2, int ly2,
                           const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Specified color is (null).",
                                    cimg_instance);
      if (light._depth>1 || light._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);

      if (y0>y1) cimg::swap(x0,x1,y0,y1,lx0,lx1,ly0,ly1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,lx0,lx2,ly0,ly2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,lx1,lx2,ly1,ly2);
      if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this;

      const int w1 = width() - 1, h1 = height() - 1, cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1);
      const longT
        dx01 = (longT)x1 - x0, dx02 = (longT)x2 - x0, dx12 = (longT)x2 - x1,
        dy01 = std::max((longT)1,(longT)y1 - y0),
        dy02 = std::max((longT)1,(longT)y2 - y0),
        dy12 = std::max((longT)1,(longT)y2 - y1),
        hdy01 = dy01/2, hdy02 = dy02/2, hdy12 = dy12/2,
        dlx01 = (longT)lx1 - lx0, dlx02 = (longT)lx2 - lx0, dlx12 = (longT)lx2 - lx1,
        dly01 = (longT)ly1 - ly0, dly02 = (longT)ly2 - ly0, dly12 = (longT)ly2 - ly1;
      const ulongT lwhd = (ulongT)light._width*light._height*light._depth;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Provide a 2D light image (depth == 1) whose spectrum() is >= the target image's spectrum()
  2. Convert the light texture first: light.get_resize(w,h,1,spectrum()) or get_channel(0) expanded to the right channel count
  3. If shading is not needed, omit the light texture (use the overload without light) instead of passing an unsuitable image
  4. Log light._width/_height/_depth/_spectrum (as printed in the message) and fix the mismatch

Example fix

// before
draw_triangle(x0,y0,x1,y1,x2,y2,color,0,0,0,0,0,0,grayLight); // grayLight spectrum=1, image spectrum=3
// after
CImg<T> light = grayLight.get_resize(grayLight.width(),grayLight.height(),1,3);
draw_triangle(x0,y0,x1,y1,x2,y2,color,0,0,0,0,0,0,light);
Defensive patterns

Strategy: validation

Validate before calling

if (!light || light.depth() > 1 || light.spectrum() < image.spectrum())
  light.assign(light.width(),light.height(),1,image.spectrum()); // normalize
image.draw_triangle(x0,y0,x1,y1,x2,y2,color,lx0,ly0,lx1,ly1,lx2,ly2,light,opacity);

Type guard

bool validLight = (light.depth() == 1 && light.spectrum() >= image.spectrum());

Try / catch

try { image.draw_triangle(...,light); }
catch (cimg_library::CImgArgumentException &e) { log_error("light texture invalid: %s", e.what()); }

Prevention

When it happens

Trigger: Calling draw_triangle(x0,y0,x1,y1,x2,y2,color,lx0..ly2,light,...) where `light` is a 3D (depth>1) image, or light.spectrum() < image.spectrum() (e.g. a grayscale light texture on an RGB image).

Common situations: Passing a volumetric image as the light map; reusing a light texture from a grayscale pipeline in a color (spectrum=3) draw; mixing images loaded with different channel counts.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/a2654b2d3382b190. Report an issue: GitHub.