Exemplo n.º 1
0
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);
}