void LoadPNG( Img& img, RGBx* palette, const char* filename ) { FILE *fp = fopen(filename, "rb"); if (!fp) throw Wobbly( "open failed: %s", strerror(errno) ); unsigned char header[8]; fread( header, 1, 8, fp ); bool is_png = !png_sig_cmp( header, 0, 8 ); if( !is_png ) { fclose(fp); throw Wobbly( "Not a PNG file." ); } png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL ); if( !png_ptr ) { fclose(fp); throw Wobbly( "png_create_read_struct() failed" ); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); throw Wobbly( "png_create_info_struct() failed" ); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); throw Wobbly( "png_create_info_struct() failed" ); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); throw Wobbly( "error reading PNG" ); } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width; png_uint_32 height; int color_type; int bit_depth; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL ); if( color_type != PNG_COLOR_TYPE_PALETTE ) { throw Wobbly( "PNG does not have a palette" ); } if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); // read in the image data Img tmp( Img::INDEXED8BIT, width, height ); png_bytep row_pointers[ tmp.H() ]; int y; for( y=0;y<tmp.H();++y) row_pointers[y] = (png_bytep)tmp.Ptr(0,y); png_read_image( png_ptr, row_pointers ); img.Copy(tmp); // now read in the palette png_colorp colours; int num_colours; png_get_PLTE(png_ptr, info_ptr, &colours, &num_colours); assert( num_colours <= 256 ); int i=0; while( i<num_colours ) { png_color c = colours[i]; palette[i] = RGBx( c.red, c.green, c.blue ); ++i; } // black out any missing colours while( i<=255 ) { palette[i] = RGBx(0,0,0); ++i; } png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); }