Yalantis/uCrop · error · CImgIOException

load_png(): Invalid bit depth %u in file '%s'.

Error message

load_png(): Invalid bit depth %u in file '%s'.

What it means

After reading the PNG header, CImg only supports 8-bit and 16-bit per-channel depths (bit_depth != 8 && != 16). Any other depth (1, 2, or 4 bits per pixel) causes CImgIOException, since CImg's pixel buffer cannot represent them directly.

Source

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

        bit_depth = 8;
      }
      if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type |= PNG_COLOR_MASK_ALPHA;
      }
      if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
        color_type |= PNG_COLOR_MASK_COLOR;
        is_gray = true;
      }
      if (color_type==PNG_COLOR_TYPE_RGB)
        png_set_filler(png_ptr,0xffffU,PNG_FILLER_AFTER);

      png_read_update_info(png_ptr,info_ptr);
      if (bit_depth!=8 && bit_depth!=16) {
        if (!file) cimg::fclose(nfile);
        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Invalid bit depth %u in file '%s'.",
                              cimg_instance,
                              bit_depth,nfilename?nfilename:"(FILE*)");
      }
      const int byte_depth = bit_depth>>3;

      // Allocate memory for image reading.
      png_bytep *const imgData = new png_bytep[H];
      for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[(size_t)byte_depth*4*W];
      png_read_image(png_ptr,imgData);
      png_read_end(png_ptr,end_info);

      // Read pixel data.
      if (color_type!=PNG_COLOR_TYPE_RGB && color_type!=PNG_COLOR_TYPE_RGB_ALPHA) {
        if (!file) cimg::fclose(nfile);
        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Invalid color coding type %u in file '%s'.",

View on GitHub (pinned to f788b534b4)

Solutions

  1. Re-export the image as 8-bit or 16-bit truecolor/grayscale PNG (e.g. magick input.png -depth 8 out.png).
  2. If using pngquant/oxipng, raise the minimum bit depth or skip depth reduction for files destined for CImg.
  3. Check the file with pngcheck -v or magick identify to confirm its bit depth.

Example fix

// shell: before (1/2/4-bit png) -> after
// magick icon.png -define png:color-type=6 -depth 8 icon8.png
img.load_png("icon8.png"); // now 8-bit, loads fine
Defensive patterns

Strategy: fallback

Validate before calling

// inspect IHDR bit depth (byte 24 of the file) before loading
bool supportedDepth(const char *p) {
  unsigned char h[26] = {}; std::FILE *f = std::fopen(p,"rb");
  if (!f) return false;
  size_t n = std::fread(h,1,26,f); std::fclose(f);
  return n==26 && (h[24]==8 || h[24]==16);
}

Try / catch

try { img.load_png(path); }
catch (CImgIOException &e) {
  img.load(path); // fallback loader / pre-converted 8-bit copy
}

Prevention

When it happens

Trigger: Loading a paletted or grayscale PNG stored with 1/2/4-bit depth (common for icons, small sprites, optimized PNGs) via load_png().

Common situations: Icons exported from design tools with 'PNG-8'/indexed or bit-depth-reduced settings; optimized PNGs from compressors like pngquant/oxipng; low-color screenshots.

Related errors


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