Yalantis/uCrop · error · CImgException

load_tiff(): Failed to allocate memory (%s) for file '%s'.

Error message

load_tiff(): Failed to allocate memory (%s) for file '%s'.

What it means

In the RGBA fast path, load_tiff() allocates a raster buffer of nx*ny*sizeof(cimg_uint32) bytes with _TIFFmalloc. If that allocation returns null, the library throws a CImgException naming the requested buffer size, meaning the system could not supply that much memory.

Source

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

        voxel_size[1] = 1.f/voxel_size[1];
      }
      if (description) {
        const char *s_description = 0;
        if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description)
          CImg<charT>::string(s_description).move_to(*description);
      }
      const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel;
      assign(nx,ny,1,spectrum);

      if ((photo>=3 && sampleformat==1 &&
           (bitspersample==4 || bitspersample==8) &&
           (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) ||
          (bitspersample==1 && samplesperpixel==1)) {
        // Special case for unsigned color images.
        cimg_uint32 *const raster = (cimg_uint32*)_TIFFmalloc(nx*ny*sizeof(cimg_uint32));
        if (!raster) {
          _TIFFfree(raster); TIFFClose(tif);
          throw CImgException(_cimg_instance
                              "load_tiff(): Failed to allocate memory (%s) for file '%s'.",
                              cimg_instance,
                              cimg::strbuffersize(nx*ny*sizeof(cimg_uint32)),filename);
        }
        TIFFReadRGBAImage(tif,nx,ny,raster,0);
        switch (spectrum) {
        case 1 :
          cimg_forXY(*this,x,y)
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);
          break;
        case 3 :
          cimg_forXY(*this,x,y) {
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]);
            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]);
            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]);
          }
          break;
        case 4 :

View on GitHub (pinned to f788b534b4)

Solutions

  1. Free memory or reduce concurrent allocations before loading.
  2. Downscale or crop the image before load (e.g. preprocess with tiffcp -Z or vips).
  3. Load the image on a device/process with a larger memory budget (64-bit).
  4. Use the tile/strip read path instead of the RGBA path by changing the file's storage layout.

Example fix

// before: 40000x40000 RGBA => ~6.4 GB raster
img.load_tiff("huge_scan.tif");
// after: downscale first
// $ tiffcp -Z 8000 huge_scan.tif small.tif
img.load_tiff("small.tif");
Defensive patterns

Strategy: validation

Validate before calling

long long need = (long long)width * height * 4;
if (need > availableMemoryBudget()) throw std::runtime_error("TIFF too large for memory budget");

Try / catch

try { img.load_tiff(path); }
catch (CImgException &e) { if (strstr(e.what(), "allocate memory")) downscaleThenReload(path); else throw; }

Prevention

When it happens

Trigger: Loading a very large TIFF (huge width*height) such that nx*ny*4 bytes exceeds available memory, e.g. a multi-gigapixel scan on a memory-constrained Android device.

Common situations: Mobile/JNI environments with low per-process memory limits, 32-bit address-space exhaustion, or 32-bit overflow of nx*ny*sizeof() for gigantic dimensions.

Related errors


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