Yalantis/uCrop · error · CImgIOException
load_pnm(): PNM header not found in file '%s'.
Error message
load_pnm(): PNM header not found in file '%s'.
What it means
CImg's load_pnm() parses Portable Anymap (PNM/PBM/PGM/PPM) headers. It first scans the leading line and requires it to match the magic number 'P<digit>' (e.g. P2, P6). If the first non-comment line does not parse as a PNM magic token, it throws CImgIOException, meaning the file is not a recognizable PNM image.
Source
Thrown at ucrop/src/main/jni/CImg.h:57572
static CImg<T> get_load_pnm(std::FILE *const file) {
return CImg<T>().load_pnm(file);
}
CImg<T>& _load_pnm(std::FILE *const file, const char *const filename) {
if (!file && !filename)
throw CImgArgumentException(_cimg_instance
"load_pnm(): Specified filename is (null).",
cimg_instance);
std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
unsigned int ppm_type, W, H, D = 1, colormax = 255;
CImg<charT> item(16384,1,1,1,0);
int err, rval, gval, bval;
const longT cimg_iobuffer = (longT)24*1024*1024;
while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
if (cimg_sscanf(item," P%u",&ppm_type)!=1) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_pnm(): PNM header not found in file '%s'.",
cimg_instance,
filename?filename:"(FILE*)");
}
while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
if ((err=cimg_sscanf(item," %u %u %u %u",&W,&H,&D,&colormax))<2) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.",
cimg_instance,
filename?filename:"(FILE*)");
}
if (ppm_type!=1 && ppm_type!=4) {
if (err==2 || (err==3 && (ppm_type==5 || ppm_type==7 || ppm_type==8 || ppm_type==9))) {
while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
if (cimg_sscanf(item,"%u",&colormax)!=1)
cimg::warn(_cimg_instance
"load_pnm(): COLORMAX field is undefined in file '%s'.",View on GitHub (pinned to f788b534b4)
Solutions
- Verify the file actually starts with a PNM magic number (P1-P7) by inspecting the first bytes, e.g. 'head -c 2 file.pnm'.
- Re-export or re-convert the image to PNM with a known-good tool (e.g. `convert img.jpg img.pnm`).
- Remove any leading BOM, whitespace, or junk lines before the 'P<digit>' token.
- If the file is a different format, call the matching loader (load_jpeg, load_png, ...) or plain load() instead of load_pnm.
- Wrap the load call in try/catch for CImgIOException and report the bad file to the user.
Example fix
// before
img.load_pnm(path); // crashes on non-PNM input
// after
std::ifstream f(path, std::ios::binary);
char magic[2] = {0};
f.read(magic, 2);
if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '7') {
img.load_pnm(path);
} else {
img.load(path.c_str()); // fall back to format auto-detection
} Defensive patterns
Strategy: validation
Validate before calling
bool looksLikePnm(const char* path) {
std::ifstream f(path, std::ios::binary);
char m[2] = {0};
f.read(m, 2);
return f && m[0]=='P' && m[1]>='1' && m[1]<='6';
} Type guard
bool isPnmMagic(const unsigned char* b, size_t n) {
return n >= 2 && b[0]=='P' && b[1]>='1' && b[1]<='6';
} Try / catch
try {
img.load_pnm(path);
} catch (cimg_library::CImgIOException& e) {
std::cerr << "Invalid PNM: " << e.what() << "\n";
} Prevention
- Check the first two bytes equal P1-P6 before calling load_pnm
- Never rename files between formats without converting
- Strip BOMs and leading whitespace from generated PNMs
- Use load() auto-detection when the format is unknown
When it happens
Trigger: Calling CImg<T>::load_pnm(filename) (or load() auto-detecting pnm) on a file whose first non-comment line lacks a valid 'P<type>' magic token: a truncated/corrupted PNM, a renamed non-PNM file (e.g. a JPEG renamed to .pnm), an empty file, or a file starting with garbage/extra bytes before the magic number.
Common situations: Files misnamed during download or conversion pipelines; text editors or scripts prepending BOM/whitespace; truncated uploads; passing an SVG/JPEG file path to load_pnm directly.
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
- load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.
- load_pnm(): Specified image dimensions in file '%s' exceed f
- load_pnm(): PNM type 'P%d' found, but type is not supported.
- load_pnm(): COLORMAX field is undefined in file '%s'.
- load(): Failed to open file '%s'.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/c31842276e3064fd.
Report an issue: GitHub.