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 X-axis.

What it means

When FFTW3 is not available, CImg falls back to a built-in radix-2 FFT that only works when the dimension along the transform axis is a power of 2 (or exactly 1). For the X-axis it checks real._width via ((N-1)&N) && N!=1 and throws if width is not 2^N. This is a hard requirement of the built-in algorithm.

Solutions

  1. Pad the image width to the next power of 2 (e.g. with CImg::resize or zero-padding) before FFT.
  2. Build CImg with cimg_use_fftw3 so arbitrary dimensions are supported by FFTW.
  3. Crop the image to a power-of-two width if padding is unacceptable.
  4. Verify image dimensions with code before calling FFT.

Example fix

// before
CImg<float> img(100, 100); img.FFT(); // width 100 is not 2^N
// after
CImg<float> img(100, 100);
CImg<float> padded(img.get_resize(128, 128, -100, -100, 0));
padded.FFT();
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

try { img.FFT(is_inverse, false, 'x'); }
catch (CImgInstanceException& e) { /* pad to power of two and retry */ }

Prevention

When it happens

Trigger: Calling CImgList<T>::FFT()/CImg<T>::FFT() along the X-axis (axis='x') without cimg_use_fftw3 defined, on an image whose _width is not a power of two (e.g. 100, 333, 1000).

Common situations: Feeding camera frames or natural images of arbitrary width into FFT, forgetting to pad to a power of two, or a build that silently lacks FFTW3 so the fallback path is active.

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

Appendix: source

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

              j = realc.offset(x,y,z);
            realc[j] = (T)(a*ptrf[i]);
            imagc[j] = (T)(a*ptrf[i + 1]);
          }
        }
      }

      fftw_destroy_plan(data_plan);
      fftw_free(data_in);
#ifndef cimg_use_fftw3_singlethread
      fftw_cleanup_threads();
#endif
      cimg::mutex(12,0);
#else
      switch (_axis) {
      case 'x' : { // Fourier along X, using built-in functions
        const unsigned int N = real._width, 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 X-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_forYZC(real,y,z,c) {
              cimg::swap(real(i,y,z,c),real(j,y,z,c));
              cimg::swap(imag(i,y,z,c),imag(j,y,z,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(ri,y,z,c),real(rj,y,z,c));
                cimg::swap(imag(ri,y,z,c),imag(rj,y,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)