Yalantis/uCrop · error · CImgInstanceException

haar(): Sub-image width %u is not even.

Error message

haar(): Sub-image width %u is not even.

What it means

CImg::haar() performs a Haar wavelet transform along the X axis. For a single-scale transform it splits the width in half (w = _width/2) and requires each sub-image width to be even (w%2==0) or equal to 1; otherwise the recursive sub-division of the signal is impossible and it throws CImgInstanceException.

Solutions

  1. Use an image width that is a power of two (or ensure width/2 is even or 1).
  2. Resize/pad the image to the next power of two before calling: img.get_resize(w2,h2) or pad with zeros.
  3. Increase nb_scales to use the multi-scale version, which handles sizes differently.
  4. Compute the largest valid scale: only descend while (dim/2) is even.

Example fix

// before
CImg<> out = img6x8.get_haar('x', false, 1); // width 6 -> half 3, odd
// after
CImg<> padded = img6x8.get_resize(8, img6x8.height());
CImg<> out = padded.get_haar('x', false, 1);
Defensive patterns

Strategy: validation

Validate before calling

if (unsigned w = img.width()/2; (w % 2) && w != 1) img = img.get_resize(nextPow2(img.width()), img.height());

Type guard

bool haarXOk(const CImg<T>& img) {
  unsigned w = img.width()/2;
  return w == 0 || !(w % 2) || w == 1;
}

Try / catch

try {
  res = img.get_haar('x', invert, nb_scales);
} catch (const CImgInstanceException& e) {
  res = img.get_resize(pow2ceil(img.width()), img.height()).get_haar('x', invert, nb_scales);
}

Prevention

When it happens

Trigger: Calling img.get_haar('x', invert, nb_scales=1) when the half-width (width/2) is odd and greater than 1 — e.g. width = 6, 10, 14 (half = 3, 5, 7) or any width where width/2 is odd.

Common situations: Applying the Haar transform to arbitrarily sized images (e.g. odd or non-power-of-two widths from a camera or crop), passing nb_scales=1 on an image whose width/2 is odd, inverting a transform applied to a resized image.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

       \param invert Set inverse of direct transform.
       \param nb_scales Number of scales used for the transform.
    **/
    CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
      return get_haar(axis,invert,nb_scales).move_to(*this);
    }

    //! Compute Haar multiscale wavelet transform \newinstance.
    CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
      if (is_empty() || !nb_scales) return +*this;
      CImg<Tfloat> res;
      const Tfloat sqrt2 = std::sqrt(2.f);
      if (nb_scales==1) {
        switch (cimg::lowercase(axis)) { // Single scale transform
        case 'x' : {
          const unsigned int w = _width/2;
          if (w) {
            if ((w%2) && w!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image width %u is not even.",
                                          cimg_instance,
                                          w);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X
              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(xw,y,z,c);
                res(x2++,y,z,c) = (val0 - val1)/sqrt2;
                res(x2++,y,z,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forYZC(*this,y,z,c) { // Direct transform along X
              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
                const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,c), val1 = (Tfloat)(*this)(x2++,y,z,c);
                res(x,y,z,c) = (val0 + val1)/sqrt2;
                res(xw,y,z,c) = (val1 - val0)/sqrt2;
              }
            }

View on GitHub (pinned to f788b534b4)