Yalantis/uCrop · error · CImgArgumentException

[cimg_appname_math_parser] CImg<%s>::%s: %s: Cannot crop emp

Error message

[cimg_appname_math_parser] CImg<%s>::%s: %s: Cannot crop empty image when some xyzc-coordinates are unspecified, in expression '%s'.

What it means

CImg's math parser (used by expressions like fill, crop, or index-based access) throws this when an expression attempts to crop an image whose instance is empty (zero dimensions) while some x/y/z/c coordinates are left unspecified, so defaults would have to be taken from the image's own dimensions. The parser checks `if (!img)` before resolving unspecified coordinates and aborts with CImgArgumentException rather than producing an undefined crop. It is a defensive guard: an empty image has no geometry to substitute for omitted coordinates.

Source

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

                  opcode[6] = (ulongT)mem[opcode[6]];
                }
                if (opcode[7]!=(ulongT)~0U) {
                  _cimg_mp_check_const_scalar((unsigned int)opcode[7],arg1 + 3,3);
                  opcode[7] = (ulongT)mem[opcode[7]];
                }
                _cimg_mp_check_type((unsigned int)opcode[8],arg1 + 4,1,0);

                if (opcode[4]==(ulongT)~0U || opcode[5]==(ulongT)~0U ||
                    opcode[6]==(ulongT)~0U || opcode[7]==(ulongT)~0U) {
                  p2 = 0;
                  if (p1!=~0U) {
                    _cimg_mp_check_const_scalar(p1,1,1);
                    p2 = (unsigned int)cimg::mod((int)mem[p1],imglist.width());
                  }
                  const CImg<T> &img = p1!=~0U?imglist[p2]:imgin;
                  if (!img) {
                    _cimg_mp_strerr;
                    throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                                "CImg<%s>::%s: %s: Cannot crop empty image when "
                                                "some xyzc-coordinates are unspecified, in expression '%s'.",
                                                pixel_type(),_cimg_mp_calling_function,s_op,s0);
                  }
                  if (opcode[4]==(ulongT)~0U) opcode[4] = (ulongT)img._width;
                  if (opcode[5]==(ulongT)~0U) opcode[5] = (ulongT)img._height;
                  if (opcode[6]==(ulongT)~0U) opcode[6] = (ulongT)img._depth;
                  if (opcode[7]==(ulongT)~0U) opcode[7] = (ulongT)img._spectrum;
                }

                pos = vector((unsigned int)(opcode[4]*opcode[5]*opcode[6]*opcode[7]));
                CImg<ulongT>::vector((ulongT)mp_image_crop,
                                     pos,p1, // 1-2: res,#ind
                                     *opcode,opcode[1],opcode[2],opcode[3], // 3-6: x,y,z,c
                                     opcode[4],opcode[5],opcode[6],opcode[7], // 7-10: dx,dy,dz,dc
                                     opcode[8]).move_to(code); // 11: boundary conditions

              } else { // Vector crop

View on GitHub (pinned to f788b534b4)

Solutions

  1. Check that the target image is non-empty before evaluating the expression: `if (img && !img.is_empty()) ...`
  2. Verify the image-list index p2 resolves to the intended, populated image (print imglist.size() and img.width()).
  3. Specify all four x/y/z/c coordinates explicitly so the parser does not need to default them from the empty image's geometry.
  4. Debug upstream steps in the expression pipeline that emptied the image (failed load, crop with zero extent).

Example fix

// before
img.crop(10,10); // img may be empty -> parser throws
// after
if (!img.is_empty()) img.crop(10,10, x, y, z, c); // or guard upstream load
Defensive patterns

Strategy: validation

Validate before calling

// before evaluating the expression
if (img.is_empty()) throw std::runtime_error("source image is empty; skip crop expression");
// CImg API
cimg_for(imglist, ptr, T) if (ptr->is_empty()) ... handle ...;

Type guard

template<typename T>
bool is_cropable(const CImg<T>& im) { return !im.is_empty(); }

Try / catch

try {
  img.crop(x, y, z, c);
} catch (const CImgArgumentException& e) {
  // empty-image crop guard: log and fall back to original image
  result = img;
}

Prevention

When it happens

Trigger: Calling crop() inside a math expression (e.g. `crop(...)` opcode in an expression like `i(x,y)`-style pipelines or `crop(ind,...)`) on image slot 0 or imglist[p2] that is empty, while omitting one or more of the x/y/z/c arguments so the parser tries to default them from img._width/_height etc. Occurs when imglist.width()>0 but the selected image is a default-constructed empty CImg, or imgin is empty.

Common situations: A G'MIC/CImg filter chain where an earlier processing step produced a zero-size image (e.g. a failed threshold or resize to 0); indexing the wrong image list slot whose entry was never assigned; loading an image from a missing/failed source and continuing to crop without checking.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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