Yalantis/uCrop · error · CImgIOException

load_bmp(): Unable to load compressed data from '(*FILE)' in

Error message

load_bmp(): Unable to load compressed data from '(*FILE)' inputs.

What it means

BMP RLE compression (types 1 and 2, i.e. 8-bit and 4-bit RLE) cannot be decoded when the image was opened from a C stdio FILE* rather than a filename, because CImg falls back to a generic decoder that needs to reopen the file by path. It throws CImgIOException in this case.

Source

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

      const int xoffset = offset - 14 - header_size - 4*nb_colors;
      if (xoffset<0 || xoffset>=file_size)
        throw CImgIOException(_cimg_instance
                              "load_bmp(): Malformed header in filename '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      cimg::fseek(nfile,xoffset,SEEK_CUR);

      CImg<ucharT> buffer;
      if (buf_size<cimg_iobuffer) {
        buffer.assign(buf_size,1,1,1,0);
        cimg::fread(buffer._data,buf_size,nfile);
      } else buffer.assign(dx_bytes + align_bytes);
      unsigned char *ptrs = buffer;

      // Decompress buffer (if necessary).
      if (compression==1 || compression==2) {
        if (file)
          throw CImgIOException(_cimg_instance
                                "load_bmp(): Unable to load compressed data from '(*FILE)' inputs.",
                                cimg_instance);
        else {
          if (!file) cimg::fclose(nfile);
          return load_other(filename);
        }
      }

      // Read pixel data.
      assign(dx,cimg::abs(dy),1,3,0);
      switch (bpp) {
      case 1 : { // Monochrome
        if (colormap._width>=2) for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          unsigned char mask = 0x80, val = 0;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Pass the filename string instead of a FILE* so CImg can route to load_other()
  2. Re-encode the BMP uncompressed (BI_RGB) before loading
  3. Convert the image to PNG and load that
  4. Read the FILE* into memory and decode with a different library

Example fix

// before
std::FILE* f = fopen("rle.bmp","rb");
img.load_bmp(f);
// after
img.load_bmp("rle.bmp"); // path allows RLE fallback path
Defensive patterns

Strategy: fallback

Validate before calling

unsigned compression = readU32LE(path,30);
bool isRle = compression == 1 || compression == 2;
if (isRle) { /* prefer filename-based load or re-encode */ }

Type guard

bool isUncompressedBmp(unsigned biCompression) { return biCompression == 0; }

Try / catch

try { img.load_bmp(fileHandle); }
catch (CImgIOException&) { img.load_bmp("rle.bmp"); // path-based fallback
}
// or catch (CImgIOException&) { img.assign(); }

Prevention

When it happens

Trigger: Calling load_bmp(std::FILE*) or load_bmp from an in-memory/FILE handle on an RLE-compressed BMP (biCompression == BI_RLE8 or BI_RLE4).

Common situations: Passing a memory-backed or already-opened FILE* (common in JNI/uCrop pipelines) instead of a filename when the BMP is RLE compressed.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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