Yalantis/uCrop · error · CImgInstanceException

CImgList< >::FFT(): Specified real and imaginary parts…

Error message

CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) have non 2^N dimension along the Y-axis.

What it means

Same built-in radix-2 constraint as the X-axis case, but applied to real._height: when FFT() computes along the Y-axis (axis='y') without FFTW3, the height must be 1 or a power of 2, otherwise this CImgInstanceException is thrown. The check is ((N-1)&N) && N!=1 with N=real._height.

Solutions

  1. Pad/crop the image height to the next power of 2 before the FFT.
  2. Compile with cimg_use_fftw3 to lift the power-of-two restriction.
  3. Resize the image (CImg::resize) to power-of-two dimensions.
  4. Pre-check height: if ((h & (h-1)) != 0) pad first.

Example fix

// before
img.FFT(true, false, 'y'); // height 1080 not 2^N
// after
const unsigned int h2 = 1; while (h2 < img.height()) h2 <<= 1;
img.get_resize(img.width(), h2, -100, -100, 0).FFT(true, false, 'y');
Defensive patterns

Strategy: validation

Validate before calling

unsigned int h = img.height();
bool isPow2 = h == 1 || ((h & (h - 1)) == 0);
if (!isPow2) img.resize(img.width(), nextPow2(h), img.depth(), img.spectrum(), 0);

Type guard

bool isPowerOfTwo(unsigned int n) { return n == 1 || (n && !(n & (n - 1))); }

Try / catch

try { img.FFT(is_inverse, false, 'y'); }
catch (CImgInstanceException& e) { /* pad height and retry */ }

Prevention

When it happens

Trigger: Calling FFT() with axis='y' (or CImgList FFT along Y) on an image whose _height is not a power of two, in a build without cimg_use_fftw3.

Common situations: Images sized to display resolution (e.g. 1920x1080 -> height 1080 not 2^N), video frames, or scanning/sensor rows counts that are arbitrary.

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

Appendix: source

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

                T &ir = real(j,y,z,c), &ii = imag(j,y,z,c), &nir = real(nj,y,z,c), &nii = imag(nj,y,z,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_inverse) { real/=N; imag/=N; }
      } break;
      case 'y' : { // Fourier along Y, using built-in functions
        const unsigned int N = real._height, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the Y-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forXZC(real,x,z,c) {
              cimg::swap(real(x,i,z,c),real(x,j,z,c));
              cimg::swap(imag(x,i,z,c),imag(x,j,z,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(x,ri,z,c),real(x,rj,z,c));
                cimg::swap(imag(x,ri,z,c),imag(x,rj,z,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = (delta>>1);

View on GitHub (pinned to f788b534b4)