コード例 #1
0
ファイル: loader_png.cpp プロジェクト: binakot/caesaria-game
//! returns true if the file maybe is able to be loaded by this class
bool PictureLoaderPng::isALoadableFileFormat( vfs::NFile file) const
{
    if( !file.isOpen() )
        return false;

    png_byte buffer[8];
    // Read the first few bytes of the PNG file
    if( file.read(buffer, 8) != 8 )
        return false;

    // Check if it really is a PNG file
    return !png_sig_cmp(buffer, 0, 8);
}
コード例 #2
0
ファイル: loader_png.cpp プロジェクト: binakot/caesaria-game
// load in the image data
Picture PictureLoaderPng::load(vfs::NFile file , bool streaming) const
{
    if(!file.isOpen())
    {
        Logger::warning( "LOAD PNG: can't open file " + file.path().toString() );
        return Picture::getInvalid();
    }

    png_byte buffer[8];
    // Read the first few bytes of the PNG file
    if( file.read(buffer, 8) != 8 )
    {
        Logger::warning( "LOAD PNG: can't read file " + file.path().toString() );
        return Picture::getInvalid();
    }

    // Check if it really is a PNG file
    if( png_sig_cmp(buffer, 0, 8) )
    {
        Logger::warning( "LOAD PNG: not really a png " + file.path().toString() );
        return Picture::getInvalid();
    }

    // Allocate the png read struct
    png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
                          NULL, (png_error_ptr)png_cpexcept_error,
                          (png_error_ptr)png_cpexcept_warn);
    if( !png_ptr )
    {
        Logger::warning( "LOAD PNG: Internal PNG create read struct failure " + file.path().toString() );
        return Picture::getInvalid();
    }

    // Allocate the png info struct
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        Logger::warning( "LOAD PNG: Couldn't create image information for PNG file " + file.path().toString() );
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return Picture::getInvalid();
    }

    // for proper error handling
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        Logger::warning( "LOAD PNG: Error reading the PNG file. " + file.path().toString() );
        return Picture::getInvalid();
    }

    // changed by zola so we don't need to have public FILE pointers
    png_set_read_fn(png_ptr, &file, user_read_data_fcn);

    png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature

    png_read_info(png_ptr, info_ptr); // Read the info section of the png file

    unsigned int Width;
    unsigned int Height;
    int BitDepth;
    int ColorType;
    {
        // Use temporary variables to avoid passing casted pointers
        png_uint_32 w,h;
        // Extract info
        png_get_IHDR(png_ptr, info_ptr,
                     &w, &h,
                     &BitDepth, &ColorType, NULL, NULL, NULL);
        Width=w;
        Height=h;
    }

    // Convert palette color to true color
    if (ColorType==PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

    // Convert low bit colors to 8 bit colors
    if (BitDepth < 8)
    {
        if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_expand_gray_1_2_4_to_8(png_ptr);
        else
            png_set_packing(png_ptr);
    }

    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_tRNS_to_alpha(png_ptr);

    // Convert high bit colors to 8 bit colors
    if (BitDepth == 16)
        png_set_strip_16(png_ptr);

    // Convert gray color to true color
    if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);

    int intent;
    const double screen_gamma = 2.2;

    if (png_get_sRGB(png_ptr, info_ptr, &intent))
        png_set_gamma(png_ptr, screen_gamma, 0.45455);
    else
    {
        double image_gamma;
        if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
            png_set_gamma(png_ptr, screen_gamma, image_gamma);
        else
            png_set_gamma(png_ptr, screen_gamma, 0.45455);
    }

    // Update the changes in between, as we need to get the new color type
    // for proper processing of the RGBA type
    png_read_update_info(png_ptr, info_ptr);
    {
        // Use temporary variables to avoid passing casted pointers
        png_uint_32 w,h;
        // Extract info
        png_get_IHDR(png_ptr, info_ptr,
                     &w, &h,
                     &BitDepth, &ColorType, NULL, NULL, NULL);
        Width=w;
        Height=h;
    }

    // Convert RGBA to BGRA
    if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
    {
        png_set_bgr(png_ptr);
    }

    if( !Height )
    {
        Logger::warning( "LOAD PNG: Internal PNG create row pointers failure %s", file.path().toCString() );
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return Picture::getInvalid();
    }

    // Create array of pointers to rows in image data
    std::vector<unsigned char> bytes;
    int pixelSize = (ColorType==PNG_COLOR_TYPE_RGB_ALPHA ? 4 : 3);
    bytes.resize( Width * Height * pixelSize );

    ScopedArrayPtr<unsigned char*> RowPointers( (unsigned char**)new png_bytep[ Height ] );

    // Fill array of pointers to rows in image data
    unsigned char* data = &bytes[0];

    for(unsigned int i=0; i<Height; ++i)
    {
        RowPointers.data()[i] = data;
        data += Width * pixelSize;
    }

    // for proper error handling
    if( setjmp( png_jmpbuf( png_ptr ) ) )
    {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return Picture::getInvalid();
    }

    // Read data using the library function that handles all transformations including interlacing
    png_read_image( png_ptr, RowPointers.data() );

    png_read_end( png_ptr, NULL );
    png_destroy_read_struct( &png_ptr, &info_ptr, 0 ); // Clean up memory

    // Create the image structure to be filled by png data
    Picture pic;
    if( ColorType==PNG_COLOR_TYPE_RGB_ALPHA )
    {
        pic = Picture( Size( Width, Height ), bytes.data(), streaming );
    }
    else
    {
        std::vector<unsigned char> b4;
        b4.resize( Width * Height * 4 );

        for( unsigned int index=0; index < Width * Height; index++ )
        {
            b4[ index*4+3 ] = 0xff;
            b4[ index*4+0 ] = bytes[index*3+2];
            b4[ index*4+1 ] = bytes[index*3+1];
            b4[ index*4+2 ] = bytes[index*3+0];
        }

        pic = Picture( Size( Width, Height ), b4.data(), streaming );
    }
    return pic;
}