Yalantis/uCrop · error · CImgArgumentException
draw_ellipse(): Specified color is (null).
Error message
draw_ellipse(): Specified color is (null).
What it means
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.
Source
Thrown at ucrop/src/main/jni/CImg.h:52491
CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
const tc *const color, const float opacity,
const unsigned int pattern) {
CImgList<t> eig = tensor.get_symmetric_eigen();
const CImg<t> &val = eig[0], &vec = eig[1];
return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)),
std::atan2(vec(0,1),vec(0,0))*180/cimg::PI,
color,opacity,pattern);
}
template<typename tc>
CImg<T>& _draw_ellipse(const int x0, const int y0, const float radius1, const float radius2, const float angle,
const tc *const color, const float opacity,
const unsigned int pattern, const bool is_filled) {
if (is_empty() || (!is_filled && !pattern)) return *this;
const float radiusM = std::max(radius1,radius2);
if (radius1<0 || radius2<0 || x0 - radiusM>=width() || y0 + radiusM<0 || y0 - radiusM>=height()) return *this;
if (!color)
throw CImgArgumentException(_cimg_instance
"draw_ellipse(): Specified color is (null).",
cimg_instance);
const int iradius1 = (int)cimg::round(radius1), iradius2 = (int)cimg::round(radius2);
if (!iradius1 && !iradius2) return draw_point(x0,y0,color,opacity);
if (iradius1==iradius2) {
if (is_filled) return draw_circle(x0,y0,iradius1,color,opacity);
else if (pattern==~0U) return draw_circle(x0,y0,iradius1,color,opacity,pattern);
}
const float ang = (float)(angle*cimg::PI/180);
if (!is_filled) { // Outlined
const float ca = std::cos(ang), sa = std::sin(ang);
CImg<int> points((unsigned int)cimg::round(6*radiusM),2);
cimg_forX(points,k) {
const float
_ang = (float)(2*cimg::PI*k/points._width),
X = (float)(radius1*std::cos(_ang)),
Y = (float)(radius2*std::sin(_ang));View on GitHub (pinned to f788b534b4)
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.
Example fix
// before
const unsigned char* color = getColor(); // may be null
img.draw_ellipse(x,y,r1,r2,0.0f,color);
// after
const unsigned char* color = getColor();
if (!color) color = defaultWhite; // e.g. static const unsigned char def[3]={255,255,255};
img.draw_ellipse(x,y,r1,r2,0.0f,color); Defensive patterns
Strategy: validation
Validate before calling
if (!color) color = defaultColor; // before draw_ellipse // optional: assert channel count assert(sizeof(color)/sizeof(color[0]) >= img.spectrum());
Type guard
template<typename T> bool hasColor(const T* c){ return c != nullptr; } Try / catch
try { img.draw_ellipse(x,y,r1,r2,angle,color,opacity); }
catch (CImgArgumentException& e) { log_error("draw_ellipse: %s", e.what()); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- draw_rectangle(): Specified color is (null).
- draw_polygon(): Specified color is (null).
- draw_circle(): Specified color is (null).
- draw_graph(): Specified color is (null).
- draw_gaussian(): Specified color is (null).
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/5f4623a34a998c9a.
Report an issue: GitHub.