Yalantis/uCrop · error · CImgIOException

save_cimg(): CImg header not found in file '%s'.

Error message

save_cimg(): CImg header not found in file '%s'.

What it means

When saving (updating) into an existing .cimg file, save_cimg reads the first line expecting a CImg header of the form '<N>(-<pixeltype>)(-<endianness>)'. If sscanf cannot extract at least the image count and pixel type, the file is not a valid CImg file, so CImgIOException is thrown saying the header was not found.

Source

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

                                    "save_cimg(): Specified filename is (null).",
                                    cimglist_instance);
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "save_cimg(): Empty instance, for file '%s'.",
                                    cimglist_instance,
                                    filename?filename:"(FILE*)");

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
      bool saved = false, endian = cimg::endianness();
      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
      *tmp = *str_pixeltype = *str_endian = 0;
      unsigned int j, N, W, H, D, C;
      int i, err;
      j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
      err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z123468_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype._data,str_endian._data);
      if (err<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "save_cimg(): CImg header not found in file '%s'.",
                              cimglist_instance,
                              filename?filename:"(FILE*)");
      }
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
      const unsigned int lmax = std::min(N,n0 + _width);
      _cimg_save_cimg_case("bool",0,0,cimg_uint8);
      _cimg_save_cimg_case("uint8","unsigned_char","uchar",cimg_uint8);
      _cimg_save_cimg_case("int8",0,0,cimg_int8);
      _cimg_save_cimg_case("char",0,0,char);
      _cimg_save_cimg_case("uint16","unsigned_short","ushort",cimg_uint16);
      _cimg_save_cimg_case("int16","short",0,cimg_int16);
      _cimg_save_cimg_case("uint32","unsigned_int","uint",cimg_uint32);
      _cimg_save_cimg_case("int32","int",0,cimg_int32);
      _cimg_save_cimg_case("uint64","unsigned_int64",0,cimg_uint64);
      _cimg_save_cimg_case("int64",0,0,cimg_int64);
      _cimg_save_cimg_case("float","float32",0,cimg_float32);

View on GitHub (pinned to f788b534b4)

Solutions

  1. Verify the target file actually starts with a valid CImg header (e.g. '3(unsigned_char)(little) ...') before updating it.
  2. Recreate the file by saving with a fresh save_cimg call instead of updating an incompatible file.
  3. Check that the previous writer used CImg and that the file is not truncated (non-zero size).

Example fix

// before
list.save_cimg("data.bin"); // not a CImg file
// after
std::FILE *f = std::fopen("data.bin","rb");
bool ok = f && std::fgetc(f)!='#' ? false : true; // crude header sniff
if (f) std::fclose(f);
if (!ok) std::remove("data.bin");
list.save_cimg("data.bin");
Defensive patterns

Strategy: validation

Validate before calling

// verify the file begins with a CImg header before updating
std::FILE *f = std::fopen(path, "rb");
bool ok = false;
if (f) { char h[16] = {0}; ok = std::fread(h,1,15,f) > 0 && h[0] >= '0' && h[0] <= '9'; std::fclose(f); }
if (!ok) std::remove(path);

Try / catch

try { list.save_cimg(path); } catch (CImgIOException &e) { std::remove(path); list.save_cimg(path); }

Prevention

When it happens

Trigger: Pointing save_cimg at a file that is not a .cimg file (wrong extension, text/binary mismatch); a truncated file whose first line is missing; a file written by another tool with a different header format.

Common situations: Extension/content mismatch (renamed a raw file to .cimg); crash during a previous write left a zero-length file; cross-version format differences.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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