Yalantis/uCrop · error · CImgArgumentException

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

Error message

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

What it means

This texture-mapped draw_triangle() overload requires the texture to be a 2D image whose spectrum (channels) is at least as large as the instance's _spectrum. When texture._depth>1 (a volumetric texture) or texture._spectrum<_spectrum (too few channels), the mapping is undefined, so the library throws CImgArgumentException including the texture's (w,h,d,s,ptr).

Source

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

       \param ty1 Y-coordinate of the second vertex in the texture image.
       \param tx2 X-coordinate of the third vertex in the texture image.
       \param ty2 Y-coordinate of the third vertex in the texture image.
       \param opacity Drawing opacity.
       \param brightness Brightness factor of the drawing (in [0,2]).
    **/
    template<typename tc>
    CImg<T>& draw_triangle(int x0, int y0,
                           int x1, int y1,
                           int x2, int y2,
                           const CImg<tc>& texture,
                           int tx0, int ty0,
                           int tx1, int ty1,
                           int tx2, int ty2,
                           const float opacity=1,
                           const float brightness=1) {
      if (is_empty()) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);

      if (y0>y1) cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,tx0,tx2,ty0,ty2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,tx1,tx2,ty1,ty2);
      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,

View on GitHub (pinned to f788b534b4)

Solutions

  1. Convert the texture to match: texture.resize(-100,-100,1,img._spectrum) before drawing
  2. If the texture is 3D, select a slice: texture.get_slice(z) and pass that
  3. Use channel_append/resize to add missing channels to a grayscale texture
  4. Check texture._depth==1 && texture._spectrum>=img._spectrum before calling

Example fix

// before
CImg<unsigned char> tex = atlas.get_slice(z); tex = gray; // spectrum 1
img.draw_triangle(x0,y0,x1,y1,x2,y2,tex,tx0,ty0,tx1,ty1,tx2,ty2); // img is RGB
// after
CImg<unsigned char> tex = atlas.get_slice(z);
tex.resize(-100,-100,1,img._spectrum); // now 3 channels
img.draw_triangle(x0,y0,x1,y1,x2,y2,tex,tx0,ty0,tx1,ty1,tx2,ty2);
Defensive patterns

Strategy: validation

Validate before calling

if (!texture.is_empty() && texture._depth==1 && texture._spectrum>=img._spectrum) { img.draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); }

Type guard

template<typename T,typename U> bool validTexture(const CImg<T>& tex, const CImg<U>& img) { return tex._depth==1 && tex._spectrum>=img._spectrum && !tex.is_empty(); }

Try / catch

try { img.draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); } catch (const CImgArgumentException& e) { /* convert texture and retry */ }

Prevention

When it happens

Trigger: Calling draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,...) with a 3D (depth>1) texture, or a grayscale texture when drawing into an RGB(A) image, or an empty texture.

Common situations: Passing an RGB image instance but a single-channel texture; accidentally passing the whole texture atlas volume instead of a slice; texture image not converted (e.g. L vs RGB) after loading.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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