Yalantis/uCrop · error · CImgIOException

CImg<%s>::load_inr(): INRIMAGE-4 header not found.

Error message

CImg<%s>::load_inr(): INRIMAGE-4 header not found.

What it means

CImg's INR (INRIMAGE-4) loader requires the file to begin with the magic token '#INRIMAGE-4#{'. _load_inr_header() reads the first token via fscanf and, if strncasecmp against that magic fails, throws this exception. It means the file is not an INRIMAGE-4 file (or the magic line is corrupted).

Source

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

    }

    //! Load image from an INRIMAGE-4 file \overloading.
    CImg<T>& load_inr(std::FILE *const file, float *const voxel_size=0) {
      return _load_inr(file,0,voxel_size);
    }

    //! Load image from an INRIMAGE-4 file \newinstance.
    static CImg<T> get_load_inr(std::FILE *const file, float *voxel_size=0) {
      return CImg<T>().load_inr(file,voxel_size);
    }

    static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) {
      CImg<charT> item(1024), tmp1(64), tmp2(64);
      *item = *tmp1 = *tmp2 = 0;
      out[0] = std::fscanf(file,"%63s",item._data);
      out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
      if (cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
        throw CImgIOException("CImg<%s>::load_inr(): INRIMAGE-4 header not found.",
                              pixel_type());

      while (std::fscanf(file," %63[^\n]%*c",item._data)!=EOF && std::strncmp(item,"##}",3)) {
        cimg_sscanf(item," XDIM%*[^0-9]%d",out);
        cimg_sscanf(item," YDIM%*[^0-9]%d",out + 1);
        cimg_sscanf(item," ZDIM%*[^0-9]%d",out + 2);
        cimg_sscanf(item," VDIM%*[^0-9]%d",out + 3);
        cimg_sscanf(item," PIXSIZE%*[^0-9]%d",out + 6);
        if (voxel_size) {
          cimg_sscanf(item," VX%*[^0-9.+-]%f",voxel_size);
          cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1);
          cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2);
        }
        if (cimg_sscanf(item," CPU%*[ =]%s",tmp1._data)) out[7] = cimg::strncasecmp(tmp1,"sun",3)?0:1;
        switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1._data,tmp2._data)) {
        case 0 : break;
        case 2 :
          out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Check the first 13 bytes of the file equal '#INRIMAGE-4#{' before calling load_inr().
  2. Convert the file to INRIMAGE-4 (or another supported format) using the original tool (e.g. InrImage/Greyscale conversion utilities).
  3. Verify the extension matches the real format and let CImg auto-detect via load() with the correct extension.
  4. If the file starts with a BOM or extra whitespace/newline, strip it — the magic must be the first token.
  5. Catch CImgIOException and attempt alternative loaders based on magic-byte sniffing.

Example fix

// before
img.load_inr("volume.inr"); // actually a DICOM file renamed
// after
std::FILE* f = std::fopen("volume.inr","rb"); char magic[14] = {0};
std::fread(magic,1,13,f); std::fclose(f);
if (std::strncmp(magic, "#INRIMAGE-4#{", 13) == 0) img.load_inr("volume.inr");
else img.load_medcon_external("volume.inr"); // or proper converter
Defensive patterns

Strategy: validation

Validate before calling

bool isInrImage(const std::string& path) {
  std::FILE* f = std::fopen(path.c_str(), "rb"); if (!f) return false;
  char magic[14] = {0}; std::fread(magic, 1, 13, f); std::fclose(f);
  return cimg::strncasecmp(magic, "#INRIMAGE-4#{", 13) == 0;
}

Type guard

bool hasInrMagic(const char* magic) { return magic && std::strncmp(magic, "#INRIMAGE-4#{", 13) == 0; }

Try / catch

try { img.load_inr(path); }
catch (CImgIOException& e) { fprintf(stderr, "Not INRIMAGE-4, sniffing real format...\n"); img.load(path.c_str()); }

Prevention

When it happens

Trigger: Calling CImg::load_inr() or load() on a file dispatched as .inr/.inr.gz whose first bytes are not '#INRIMAGE-4#{' — e.g. a DICOM/PNM file renamed to .inr, or an older INRIMAGE-3 header.

Common situations: Wrong extension routing in load(): a data file with .inr extension that is actually another format; gzipped INR handled elsewhere and passed raw; files re-saved by tools that dropped the header comment block.

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/38774b50ac945a03. Report an issue: GitHub.