Yalantis/uCrop · error · CImgIOException
load_png(): Invalid PNG file '%s'.
Error message
load_png(): Invalid PNG file '%s'.
What it means
After opening the file, CImg reads the first 8 bytes and calls libpng's png_sig_cmp(); if the bytes do not match the PNG signature, the file is not a PNG and CImgIOException is thrown with the filename (or '(FILE*)').
Source
Thrown at ucrop/src/main/jni/CImg.h:57386
throw CImgIOException(_cimg_instance
"load_png(): Unable to load data from '(FILE*)' unless libpng is enabled.",
cimg_instance);
else return load_other(filename);
#else
// Open file and check for PNG validity.
#if defined __GNUC__
const char *volatile nfilename = filename; // Use 'volatile' to avoid (wrong) g++ warning
std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
#else
const char *nfilename = filename;
std::FILE *nfile = file?file:cimg::fopen(nfilename,"rb");
#endif
unsigned char pngCheck[8] = {};
cimg::fread(pngCheck,8,(std::FILE*)nfile);
if (png_sig_cmp(pngCheck,0,8)) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_png(): Invalid PNG file '%s'.",
cimg_instance,
nfilename?nfilename:"(FILE*)");
}
// Setup PNG structures for read.
png_voidp user_error_ptr = 0;
png_error_ptr user_error_fn = 0, user_warning_fn = 0;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
if (!png_ptr) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_png(): Failed to initialize 'png_ptr' structure for file '%s'.",
cimg_instance,
nfilename?nfilename:"(FILE*)");
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {View on GitHub (pinned to f788b534b4)
Solutions
- Verify the file really is a PNG (file photo.png, or check the 8-byte header \x89PNG\r\n\x1a\n yourself).
- Convert/re-export the image to PNG (e.g. magick input.jpg output.png).
- If the source is a URL, check the response was a real image (status 200, correct content-type) before saving.
- Check the file is not empty or truncated (size > 8 bytes).
Example fix
// before
img.load_png(path); // path may hold a JPEG
// after
unsigned char sig[8] = {};
std::FILE *f = std::fopen(path, "rb");
if (f) { std::fread(sig,1,8,f); std::fclose(f); }
if (sig[0]==0x89 && sig[1]=='P') img.load_png(path);
else img.load(path); // let CImg sniff the real format Defensive patterns
Strategy: validation
Validate before calling
bool isPng(const char *p) {
unsigned char s[8] = {};
std::FILE *f = std::fopen(p, "rb");
if (!f) return false;
size_t n = std::fread(s,1,8,f); std::fclose(f);
return n == 8 && std::memcmp(s, "\x89PNG\r\n\x1a\n", 8) == 0;
} Type guard
bool looksLikePng(const unsigned char *hdr, size_t n) {
return n >= 8 && std::memcmp(hdr, "\x89PNG\r\n\x1a\n", 8) == 0;
} Try / catch
try { img.load_png(path); }
catch (CImgIOException &e) { std::fprintf(stderr, "Not a PNG: %s\n", path); img.load(path); } Prevention
- Check the magic bytes before calling a format-specific loader
- Never trust file extensions; sniff content
- Validate downloaded images (HTTP status + content-type) before saving
When it happens
Trigger: load_png() pointing at a JPEG/GIF/BMP/WebP file, a text/HTML error page saved with a .png extension, a truncated or zero-byte file, or an SVG named .png.
Common situations: Wrong extension after renaming files, a download that saved an error page, a URL fetch that returned JSON/HTML instead of image bytes, empty placeholder files in test fixtures.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- load_bmp(): Invalid offset %d specified in filename '%s'.
- load_bmp(): File size %lu for filename '%s' does not match e
- load_bmp(): Malformed header in filename '%s'.
- load_jpeg(): Error message returned by libjpeg: %s.
- load_jxl(): Failed to decode image '%s'.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/994e6dd1c4528ee0.
Report an issue: GitHub.