{"record":{"id":"5f4623a34a998c9a","repo":"Yalantis/uCrop","slug":"draw-ellipse-specified-color-is-null","errorCode":null,"errorMessage":"draw_ellipse(): Specified color is (null).","messagePattern":"draw_ellipse\\(\\): Specified color is \\(null\\)\\.","errorType":"validation","errorClass":"CImgArgumentException","httpStatus":null,"severity":"error","filePath":"ucrop/src/main/jni/CImg.h","lineNumber":52491,"sourceCode":"    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,\n                          const tc *const color, const float opacity,\n                          const unsigned int pattern) {\n      CImgList<t> eig = tensor.get_symmetric_eigen();\n      const CImg<t> &val = eig[0], &vec = eig[1];\n      return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)),\n                          std::atan2(vec(0,1),vec(0,0))*180/cimg::PI,\n                          color,opacity,pattern);\n    }\n\n    template<typename tc>\n    CImg<T>& _draw_ellipse(const int x0, const int y0, const float radius1, const float radius2, const float angle,\n                           const tc *const color, const float opacity,\n                           const unsigned int pattern, const bool is_filled) {\n      if (is_empty() || (!is_filled && !pattern)) return *this;\n      const float radiusM = std::max(radius1,radius2);\n      if (radius1<0 || radius2<0 || x0 - radiusM>=width() || y0 + radiusM<0 || y0 - radiusM>=height()) return *this;\n      if (!color)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_ellipse(): Specified color is (null).\",\n                                    cimg_instance);\n      const int iradius1 = (int)cimg::round(radius1), iradius2 = (int)cimg::round(radius2);\n      if (!iradius1 && !iradius2) return draw_point(x0,y0,color,opacity);\n      if (iradius1==iradius2) {\n        if (is_filled) return draw_circle(x0,y0,iradius1,color,opacity);\n        else if (pattern==~0U) return draw_circle(x0,y0,iradius1,color,opacity,pattern);\n      }\n      const float ang = (float)(angle*cimg::PI/180);\n\n      if (!is_filled) { // Outlined\n        const float ca = std::cos(ang), sa = std::sin(ang);\n        CImg<int> points((unsigned int)cimg::round(6*radiusM),2);\n        cimg_forX(points,k) {\n          const float\n            _ang = (float)(2*cimg::PI*k/points._width),\n            X = (float)(radius1*std::cos(_ang)),\n            Y = (float)(radius2*std::sin(_ang));","sourceCodeStart":52473,"sourceCodeEnd":52509,"githubUrl":"https://github.com/Yalantis/uCrop/blob/f788b534b48c144edf786c8cddbf0e029e637804/ucrop/src/main/jni/CImg.h#L52473-L52509","documentation":"draw_ellipse() requires a pointer to a color buffer (at least spectrum() elements) and throws CImgArgumentException when that pointer is null. CImg draw routines deliberately guard against null colors because pixels would otherwise be written from an invalid read. The check happens after cheap early-outs (empty image, unfilled-with-empty-pattern, off-canvas), so a valid on-canvas call with color==0 throws.","triggerScenarios":"Calling img.draw_ellipse(x0,y0,r1,r2,angle,NULL) or passing an uninitialized/unassigned color pointer, e.g. a pointer to a deleted or never-allocated buffer, or 0 literal in a code path where the color argument was conditionally computed.","commonSituations":"Color loaded from config or computed at runtime and the load failed silently leaving nullptr; calling a draw overload with the wrong argument order so that what lands in the color slot is null; C# / JNI wrappers passing null byte arrays for the color.","solutions":["Pass a valid color buffer, e.g. const unsigned char col[]={255,0,0}; sized to at least img.spectrum() channels.","Check that the variable holding the color is actually assigned before the draw call (guard for null).","If drawing with opacity only and no color makes sense in your code, restructure: color is mandatory, so supply one (e.g. white/black).","When wrapping CImg from JNI/managed code, convert the managed color array to a native pointer and reject null before crossing the boundary."],"exampleFix":"// before\nconst unsigned char* color = getColor(); // may be null\nimg.draw_ellipse(x,y,r1,r2,0.0f,color);\n// after\nconst unsigned char* color = getColor();\nif (!color) color = defaultWhite; // e.g. static const unsigned char def[3]={255,255,255};\nimg.draw_ellipse(x,y,r1,r2,0.0f,color);","handlingStrategy":"validation","validationCode":"if (!color) color = defaultColor; // before draw_ellipse\n// optional: assert channel count\nassert(sizeof(color)/sizeof(color[0]) >= img.spectrum());","typeGuard":"template<typename T> bool hasColor(const T* c){ return c != nullptr; }","tryCatchPattern":"try { img.draw_ellipse(x,y,r1,r2,angle,color,opacity); }\ncatch (CImgArgumentException& e) { log_error(\"draw_ellipse: %s\", e.what()); }","preventionTips":["Never pass literal 0/NULL for color in CImg draw calls.","Resolve theme colors through a function that always returns a default on miss.","Check pointer validity after dynamic allocation/free of color buffers.","In JNI wrappers, throw a clear error for null color arrays before native calls."],"tags":["cimg","image-processing","null-pointer"],"backgroundTag":"null-argument","analyzedSha":"f788b534b48c144edf786c8cddbf0e029e637804","analyzedAt":"2026-09-08T08:36:04.887Z","contentChangedAt":"2026-09-08T08:36:04.887Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}