Yalantis/uCrop · error · CImgIOException

load_bmp(): Malformed header in filename '%s'.

Error message

load_bmp(): Malformed header in filename '%s'.

What it means

After reading the colormap, load_bmp() derives the remaining pixel offset (xoffset = offset - 14 - header_size - 4*nb_colors) and rejects the file when this value is negative or exceeds the file size. It indicates internal header fields (offset, header_size, palette size) that are mutually inconsistent.

Source

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

        align_bytes = (4 - dx_bytes%4)%4;
      const ulongT
        cimg_iobuffer = (ulongT)24*1024*1024,
        buf_size = (ulongT)cimg::abs(dy)*(dx_bytes + align_bytes);

      if (buf_size>=fsiz)
        throw CImgIOException(_cimg_instance
                              "load_bmp(): File size %lu for filename '%s' does not match "
                              "encoded image dimensions (%d,%d).",
                              cimg_instance,
                              (long)fsiz,filename?filename:"(FILE*)",dx,dy);

      CImg<intT> colormap;
      if (bpp<16) { if (!nb_colors) nb_colors = 1<<bpp; } else nb_colors = 0;
      if (nb_colors) { colormap.assign(nb_colors); cimg::fread(colormap._data,nb_colors,nfile); }

      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);

View on GitHub (pinned to f788b534b4)

Solutions

  1. Re-export the BMP with a standard encoder (e.g. ImageMagick: convert in.png out.bmp)
  2. Use PNG instead of BMP to avoid legacy header quirks
  3. Inspect the header with a hex editor to confirm bfOffBits and biSize consistency
  4. Validate the header fields yourself before calling load_bmp

Example fix

// before
img.load_bmp("odd_header.bmp");
// after
// re-export with standard encoder first, then:
img.load_bmp("odd_header_fixed.bmp"); // convert odd_header.bmp fixed.bmp
Defensive patterns

Strategy: validation

Validate before calling

unsigned offset = readU32LE(path,10);
unsigned headerSize = readU32LE(path,14);
if (offset < 14 + headerSize) throw std::runtime_error("inconsistent bmp header");

Type guard

bool hasConsistentBmpHeader(unsigned offset, unsigned headerSize, unsigned nbColors) { return offset >= 14u + headerSize + 4u*nbColors; }

Try / catch

try { img.load_bmp(path); }
catch (CImgIOException&) { img.load(convertToPng(path)); }

Prevention

When it happens

Trigger: Loading a .bmp whose bfOffBits does not equal 14 + biSize + palette bytes; a header_size > 40 with mismatched offset; a palette-size field inconsistent with the actual offset.

Common situations: Non-standard BMP variants (OS/2 vs Windows headers), files written by buggy encoders, corrupted downloads, files with padding bytes the encoder accounted for differently.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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