Yalantis/uCrop · error · CImgArgumentException

haar(): Invalid specified axis '%c' (should be { x | y | z }

Error message

haar(): Invalid specified axis '%c' (should be { x | y | z }).

What it means

In the single-scale branch of CImg::haar(), the axis argument (lowercased) is dispatched with a switch over 'x', 'y', 'z'. Any other character reaches the default case and raises CImgArgumentException, because the transform can only run along one of the three spatial axes.

Source

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

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forXYC(*this,x,y,c) { // Inverse transform along Z
              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,y,zd,c);
                res(x,y,z2++,c) = (val0 - val1)/sqrt2;
                res(x,y,z2++,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forXYC(*this,x,y,c) {
              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { // Direct transform along Z
                const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,c), val1 = (Tfloat)(*this)(x,y,z2++,c);
                res(x,y,z,c)  = (val0 + val1)/sqrt2;
                res(x,y,zd,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        default :
          throw CImgArgumentException(_cimg_instance
                                      "haar(): Invalid specified axis '%c' "
                                      "(should be { x | y | z }).",
                                      cimg_instance,
                                      axis);
        }
      } else { // Multi-scale version
        if (invert) {
          res.assign(*this,false);
          switch (cimg::lowercase(axis)) {
          case 'x' : {
            unsigned int w = _width;
            for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2;
            for (w = w?w:1; w<=_width; w*=2) res.draw_image(res.get_crop(0,w - 1).get_haar('x',true,1));
          } break;
          case 'y' : {
            unsigned int h = _width;
            for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2;
            for (h = h?h:1; h<=_height; h*=2) res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',true,1));

View on GitHub (pinned to f788b534b4)

Solutions

  1. Pass exactly 'x', 'y' or 'z' (case-insensitive) as the axis argument.
  2. Sanitize/validate user input to a whitelisted axis before calling.
  3. Clamp a dimension index to an axis: {0:'x',1:'y',2:'z'} mapping.
  4. Initialize the axis variable to a valid default such as 'x'.

Example fix

// before
img.get_haar('w', false, 1); // invalid axis
// after
img.get_haar('x', false, 1);
Defensive patterns

Strategy: validation

Validate before calling

if (axis!='x' && axis!='y' && axis!='z') throw std::invalid_argument("haar axis must be x, y or z");

Type guard

bool isHaarAxis(char axis) {
  char a = std::tolower((unsigned char)axis);
  return a=='x' || a=='y' || a=='z';
}

Try / catch

try {
  res = img.get_haar(axis, invert, nb_scales);
} catch (const CImgArgumentException& e) {
  axis = 'x'; // safe default, log the bad input
  res = img.get_haar(axis, invert, nb_scales);
}

Prevention

When it happens

Trigger: Calling img.get_haar(axis, invert, 1) with axis not in {'x','X','y','Y','z','Z'} — e.g. 'w' for width, '0', '\0' (uninitialized char), or a variable set from misparsed user input.

Common situations: Mapping a user-facing string ('horizontal'/'width') to an axis char incorrectly; passing the dimension index instead of a char; uninitialized or defaulted axis variables in wrapper code.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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