Yalantis/uCrop · error · CImgIOException

load_png(): Invalid color coding type %u in file '%s'.

Error message

load_png(): Invalid color coding type %u in file '%s'.

What it means

CImg's load_png only handles PNG_COLOR_TYPE_RGB and PNG_COLOR_TYPE_RGB_ALPHA. Grayscale, palette/indexed, and grayscale+alpha images throw CImgIOException even though libpng read them fine — the loader's post-read check rejects those color types.

Source

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

        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'.",
                              cimg_instance,
                              color_type,nfilename?nfilename:"(FILE*)");
      }
      const bool is_alpha = (color_type==PNG_COLOR_TYPE_RGBA);
      try { assign(W,H,1,(is_gray?1:3) + (is_alpha?1:0)); }
      catch (...) { if (!file) cimg::fclose(nfile); throw; }
      T
        *ptr_r = data(0,0,0,0),
        *ptr_g = is_gray?0:data(0,0,0,1),
        *ptr_b = is_gray?0:data(0,0,0,2),
        *ptr_a = !is_alpha?0:data(0,0,0,is_gray?1:3);
      switch (bit_depth) {
      case 8 : {
        cimg_forY(*this,y) {
          const unsigned char *ptrs = (unsigned char*)imgData[y];
          cimg_forX(*this,x) {
            *(ptr_r++) = (T)*(ptrs++);

View on GitHub (pinned to f788b534b4)

Solutions

  1. Re-export as RGB or RGBA PNG: magick input.png PNG24:output.png (or PNG32 for alpha).
  2. Patch the loader to add png_set_palette_to_rgb/png_set_gray_to_rgb conversions (this custom CImg.h copy rejects them after conversion).
  3. Use img.load(path) (format auto-detect) if it routes to a more permissive loader in this build.
  4. Confirm the color type with pngcheck -v before distributing assets to the pipeline.

Example fix

// shell: convert grayscale/indexed PNG to RGBA
// magick icon.png PNG32:icon_rgba.png
img.load_png("icon_rgba.png"); // color type 6 (RGBA), accepted
Defensive patterns

Strategy: fallback

Validate before calling

// read IHDR color type (byte 25): 2=RGB, 6=RGBA are supported
bool supportedColorType(const char *p) {
  unsigned char h[27] = {}; std::FILE *f = std::fopen(p,"rb");
  if (!f) return false;
  size_t n = std::fread(h,1,27,f); std::fclose(f);
  return n==27 && (h[25]==2 || h[25]==6);
}

Try / catch

try { img.load_png(path); }
catch (CImgIOException &e) {
  img.load(path); // fallback loader may handle gray/palette
}

Prevention

When it happens

Trigger: Loading a grayscale (PNG_COLOR_TYPE_GRAY) PNG, a palette/indexed PNG-8 (icons, optimized assets), or a gray+alpha PNG via load_png().

Common situations: Black-and-white scans or screenshots saved as grayscale PNG; icons optimized to indexed color by pngquant; UI assets exported as 'PNG-8' from design tools.

Related errors


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