Yalantis/uCrop · error · CImgIOException

save_cimg(): Invalid size (%u,%u,%u,%u) of image[%u], for fi

Error message

save_cimg(): Invalid size (%u,%u,%u,%u) of image[%u], for file '%s'.

What it means

Inside the _cimg_save_cimg_case macro of CImgList::save_cimg, each image's 4D size is read back from the target file and parsed with sscanf; if the line does not yield exactly four unsigned values (W,H,D,C), the header/data in the file is malformed. The library throws CImgIOException reporting the (possibly zero) parsed size, the image index and the file. This means the .cimg file being updated/overwritten does not have the expected per-image dimension line.

Source

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

       \param is_compressed Tells if data compression must be enabled.
    **/
    const CImgList<T>& save_cimg(std::FILE *file, const bool is_compressed=false) const {
      return _save_cimg(file,0,is_compressed);
    }

    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename,
                                 const unsigned int n0,
                                 const unsigned int x0, const unsigned int y0,
                                 const unsigned int z0, const unsigned int c0) const {
#define _cimg_save_cimg_case(Ts1,Ts2,Ts3,Tss) \
      if (!saved && ((Ts1 && !cimg::strcasecmp(Ts1,str_pixeltype)) || \
                     (Ts2 && !cimg::strcasecmp(Ts2,str_pixeltype)) || \
                     (Ts3 && !cimg::strcasecmp(Ts3,str_pixeltype)))) { \
        for (unsigned int l = 0; l<lmax; ++l) { \
          j = 0; while ((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j] = 0; \
          W = H = D = C = 0; \
          if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \
            throw CImgIOException(_cimglist_instance \
                                  "save_cimg(): Invalid size (%u,%u,%u,%u) of image[%u], for file '%s'.", \
                                  cimglist_instance, \
                                  W,H,D,C,l,filename?filename:"(FILE*)"); \
          if (W*H*D*C>0) { \
            if (l<n0 || x0>=W || y0>=H || z0>=D || c0>=D) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \
            else { \
              const CImg<T>& img = (*this)[l - n0]; \
              const T *ptrs = img._data; \
              const unsigned int \
                x1 = x0 + img._width - 1, \
                y1 = y0 + img._height - 1, \
                z1 = z0 + img._depth - 1, \
                c1 = c0 + img._spectrum - 1, \
                nx1 = x1>=W?W - 1:x1, \
                ny1 = y1>=H?H - 1:y1, \
                nz1 = z1>=D?D - 1:z1, \
                nc1 = c1>=C?C - 1:c1; \
              CImg<Tss> raw(1 + nx1 - x0); \

View on GitHub (pinned to f788b534b4)

Solutions

  1. Regenerate or re-save the target .cimg file from a valid source instead of updating it in place.
  2. Validate the file's header lines (each image needs 'W H D C') before calling save_cimg in update mode.
  3. Open a fresh file: use save_cimg(filename) on a new path rather than rb+ update of a damaged file.

Example fix

// before
list.save_cimg("corrupted.cimg"); // update mode on damaged file
// after
std::remove("corrupted.cimg");
list.save_cimg("corrupted.cimg"); // fresh write, no in-place update of bad header
Defensive patterns

Strategy: validation

Validate before calling

// sniff header line before updating an existing .cimg file
std::FILE *f = std::fopen(path, "rb");
int ok = 0; unsigned W,H,D,C;
char line[256];
if (f && std::fgets(line, sizeof line, f)) ok = (std::sscanf(line, "%u %u %u %u", &W,&H,&D,&C) == 4);
if (f) std::fclose(f);
if (!ok) std::remove(path); // regenerate instead of in-place update

Try / catch

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

Prevention

When it happens

Trigger: Calling save_cimg on an existing .cimg file whose per-image header line 'W H D C' is corrupted, truncated, or in the wrong format; the file was hand-edited or produced by an incompatible writer.

Common situations: Partially written or truncated .cimg files after a crash; files manually edited; version/format mismatch where the header layout changed.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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