Yalantis/uCrop · error · CImgInstanceException

CImg<%s>::%s() [%u]: cubic_atX_p(): Empty instance.

Error message

CImg<%s>::%s() [%u]: cubic_atX_p(): Empty instance.

What it means

cubic_atX_p() is the periodic-boundary variant of cubic X-axis cubic interpolation. Like cubic_atX(), it checks is_empty() first and throws CImgInstanceException when the image has no pixels, because interpolation is undefined on an empty buffer.

Source

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

    }

    //! Return clamped pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate.
    /**
       Similar to cubic_atX(float,int,int,int) const, except that the return value is clamped to stay in the
       min/max range of the datatype \c T.
    **/
    T cubic_atX_c(const float fx, const int y, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atX(fx,y,z,c));
    }

    T _cubic_atX_c(const float fx, const int y, const int z, const int c) const {
      return cimg::type<T>::cut(_cubic_atX(fx,y,z,c));
    }

    //! Return pixel value, using cubic interpolation and periodic boundary conditions for the X-coordinate.
    Tfloat cubic_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atX_p(): Empty instance.",
                                    cimg_instance);
      return _cubic_atX_p(fx,y,z,c);
    }

    Tfloat _cubic_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const {
      const float
        nfx = cimg::type<float>::is_nan(fx)?0:cimg::mod(fx,_width - 0.5f);
      const int
        x = (int)nfx;
      const float
        dx = nfx - x;
      const int
        px = cimg::mod(x - 1,width()), nx = cimg::mod(x + 1,width()), ax = cimg::mod(x + 2,width());
      const Tfloat
        Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c),
        In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c);
      return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));

View on GitHub (pinned to f788b534b4)

Solutions

  1. Guard with if (!img.is_empty()) before calling cubic_atX_p().
  2. Validate the loaded image dimensions right after load/assign and bail out early if empty.
  3. Make upstream crop/resize code guarantee at least 1x1x1x1 dimensions.
  4. Catch CImgInstanceException around the call to fail gracefully.

Example fix

// before
CImg<unsigned char> img; // never loaded
float v = img.cubic_atX_p(1.5f);
// after
if (img && !img.is_empty()) {
  float v = img.cubic_atX_p(1.5f);
}
Defensive patterns

Strategy: validation

Validate before calling

if (img.is_empty()) return 0.f; // or handle
float v = img.cubic_atX_p(fx, y, z, c);

Type guard

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

Try / catch

try {
  float v = img.cubic_atX_p(fx);
} catch (const CImgInstanceException& e) {
  // substitute fallback value or propagate error
}

Prevention

When it happens

Trigger: Calling cubic_atX_p(fx,...) on a default-constructed CImg<T> or one with any zero dimension; passing an image whose load failed into periodic resampling/wrapping code.

Common situations: Seamless-tiling / periodic-wrapping image transforms where the source image never loaded; pipeline stages that clear() and re-assign images leaving a window where the image is empty.

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/d987b6fd8336ce9d. Report an issue: GitHub.