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
- Provide a 2D light image (depth == 1) whose spectrum() is >= the target image's spectrum()
- Convert the light texture first: light.get_resize(w,h,1,spectrum()) or get_channel(0) expanded to the right channel count
- If shading is not needed, omit the light texture (use the overload without light) instead of passing an unsuitable image
- 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
- Keep all light textures as single-channel or target-spectrum 2D images by convention
- Normalize textures (resize to depth 1, matching spectrum) at load time, not at draw time
- Print image.spectrum() and light.spectrum() in debug logs when wiring up textured draws
- Avoid passing z-buffers or volumes as light textures
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
- draw_spline(): Invalid specified texture (%u,%u,%u,%u,%p).
- draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).
- cimg::fopen(): Specified file path is (null).
- cimg::fopen(): File '%s', specified mode is (null).
- cimg::fread(): Invalid reading request of %u %s%s from file
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/a2654b2d3382b190.
Report an issue: GitHub.