Yalantis/uCrop · error · CImgArgumentException

draw_polygon(): Specified color is (null).

Error message

draw_polygon(): Specified color is (null).

What it means

CImg's filled draw_polygon(const CImg<tp>& points, const tc* color, opacity) received a null color pointer. CImg throws CImgArgumentException because polygon filling needs per-channel color values that a null pointer cannot supply.

Source

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

                      draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
      return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
        draw_line(nx1,ny0 + 1,nx1,ny1 - 1,color,opacity,pattern,false).
        draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
        draw_line(nx0,ny1 - 1,nx0,ny0 + 1,color,opacity,pattern,false);
    }

    //! Draw a filled 2D polygon.
    /**
       \param points Set of polygon vertices.
       \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color.
       \param opacity Drawing opacity.
     **/
    template<typename tp, typename tc>
    CImg<T>& draw_polygon(const CImg<tp>& points,
                          const tc *const color, const float opacity=1) {
      if (is_empty() || !points) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_polygon(): Specified color is (null).",
                                    cimg_instance);
      if (points.height()!=2)
        throw CImgArgumentException(_cimg_instance
                                    "draw_polygon(): Invalid specified point set (%u,%u,%u,%u).",
                                    cimg_instance,
                                    points._width,points._height,points._depth,points._spectrum);
      CImg<intT> ipoints;
      if (cimg::type<tp>::is_float()) ipoints = points.get_round();
      else ipoints.assign(points,cimg::type<tp>::string()==cimg::type<int>::string());

      if (ipoints._width==1) return draw_point(ipoints(0,0),ipoints(0,1),color,opacity);
      if (ipoints._width==2) return draw_line(ipoints(0,0),ipoints(0,1),ipoints(1,0),ipoints(1,1),color,opacity);
      if (ipoints._width==3) return draw_triangle(ipoints(0,0),ipoints(0,1),ipoints(1,0),ipoints(1,1),
                                                  ipoints(2,0),ipoints(2,1),color,opacity);
      cimg_init_scanline(opacity);
      int
        xmin = 0, ymin = 0,

View on GitHub (pinned to f788b534b4)

Solutions

  1. Allocate and populate the color buffer with img.spectrum() values before the call.
  2. Pass a stack array like const unsigned char color[3]={255,255,255}.
  3. Guard: if (color) draw_polygon(...); else use a default color.
  4. Verify the vector holding the color is non-empty before taking .data().

Example fix

// before
std::vector<unsigned char> col; // empty
img.draw_polygon(points, col.data(), 1.0f); // throws: null color
// after
std::vector<unsigned char> col = {255, 0, 0};
img.draw_polygon(points, col.data(), 1.0f);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!color) {
  static const unsigned char white[3] = {255, 255, 255};
  color = white;
}
img.draw_polygon(points, color, opacity);

Type guard

template <typename tc>
bool color_is_valid(const tc* color) { return color != nullptr; }

Try / catch

try {
  img.draw_polygon(points, color, opacity);
} catch (CImgArgumentException& e) {
  std::cerr << "Null polygon color: " << e.what() << std::endl;
}

Prevention

When it happens

Trigger: Calling img.draw_polygon(points, color, opacity) with color==nullptr (uninitialized buffer, empty vector's data(), or failed allocation). Note the call is silently skipped if points is empty, but a null color on non-empty points throws.

Common situations: Color array freed or never allocated; passing .data() of an empty std::vector; API migration from a value-based color API to pointer-based one.

Related errors


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