Yalantis/uCrop · warning

cimg::fread(): Only %lu/%lu elements could be read from file

Error message

cimg::fread(): Only %lu/%lu elements could be read from file.

What it means

cimg::fread() reads nmemb elements of size sizeof(T) from a C stream in bounded chunks and emits a non-fatal warning via cimg::warn() when the stream ends (or fails) before all requested elements are read. The return value still gives the number of elements actually read, so the warning signals a short read rather than an exception. CImg image-loading helpers call this when reading pixel data from files.

Source

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

       \return Number of read elements.
       \note Same as <tt>std::fread()</tt> but may display warning message if all elements could not be read.
    **/
    template<typename T>
    inline size_t fread(T *const ptr, const size_t nmemb, std::FILE *stream) {
      if (!ptr || !stream)
        throw CImgArgumentException("cimg::fread(): Invalid reading request of %u %s%s from file %p to buffer %p.",
                                    nmemb,cimg::type<T>::string(),nmemb>1?"s":"",stream,ptr);
      if (!nmemb) return 0;
      const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
      size_t to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0;
      do {
        l_to_read = (to_read*sizeof(T))<wlimitT?to_read:wlimit;
        l_al_read = std::fread((void*)(ptr + al_read),sizeof(T),l_to_read,stream);
        al_read+=l_al_read;
        to_read-=l_al_read;
      } while (l_to_read==l_al_read && to_read>0);
      if (to_read>0)
        warn("cimg::fread(): Only %lu/%lu elements could be read from file.",
             (unsigned long)al_read,(unsigned long)nmemb);
      return al_read;
    }

    //! Write data to file.
    /**
       \param ptr Pointer to memory buffer containing the binary data to write on file.
       \param nmemb Number of elements to write.
       \param[out] stream File to write data on.
       \return Number of written elements.
       \note Similar to <tt>std::fwrite</tt> but may display warning messages if all elements could not be written.
    **/
    template<typename T>
    inline size_t fwrite(const T *ptr, const size_t nmemb, std::FILE *stream) {
      if (!ptr || !stream)
        throw CImgArgumentException("cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.",
                                    nmemb,cimg::type<T>::string(),nmemb>1?"s":"",ptr,stream);
      if (!nmemb) return 0;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Check the return value of fread() against the requested element count and abort/re-throw instead of continuing with partial data
  2. Verify the file is complete (re-download/re-copy it) and its size matches what the image header advertises
  3. Validate image width/height/dimensions from the file header against the actual file size before allocating/reading
  4. Wrap the load in error handling that treats a short read as a load failure rather than using the partially filled buffer

Example fix

// before
CImg<unsigned char> img;
img.load("downloaded.png"); // silently short-reads truncated file
// after
std::FILE* f = std::fopen("downloaded.png", "rb");
std::fseek(f, 0, SEEK_END); long sz = std::ftell(f); std::fseek(f, 0, SEEK_SET);
if (sz < (long)expected_min_bytes) throw std::runtime_error("file truncated");
CImg<unsigned char> img(f);
Defensive patterns

Strategy: validation

Validate before calling

std::FILE* f = std::fopen(path, "rb");
if (!f) throw std::runtime_error("cannot open file");
std::fseek(f, 0, SEEK_END);
long sz = std::ftell(f);
std::fseek(f, 0, SEEK_SET);
if (sz < (long)sizeof(T) * expected_nmemb) throw std::runtime_error("file too small for image data");

Type guard

bool file_big_enough(std::FILE* f, size_t need_bytes) {
  long cur = std::ftell(f);
  std::fseek(f, 0, SEEK_END); long end = std::ftell(f);
  std::fseek(f, cur, SEEK_SET);
  return (size_t)(end - cur) >= need_bytes;
}

Prevention

When it happens

Trigger: Calling CImg<T>::fread()/load routines on a file that is smaller than the expected header dimensions declare, a truncated or corrupted binary image, or reading from a FILE* (pipe/network stream) that was closed early.

Common situations: Truncated downloads of image files, files corrupted mid-transfer, wrong file passed to a loader expecting a different format/size, network sockets delivered fewer bytes than the image header promised.

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