static CogFrame * cog_frame_new_from_png (void *data, int size) { struct png_data_struct s = { 0 }; png_structp png_ptr; png_infop info_ptr; png_bytep *rows; CogFrame *frame; guchar *frame_data; int j; int width, height; int color_type; png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct (png_ptr); s.data = data; s.size = size; png_set_read_fn (png_ptr, (void *) &s, read_data); png_read_info (png_ptr, info_ptr); width = png_get_image_width (png_ptr, info_ptr); height = png_get_image_height (png_ptr, info_ptr); color_type = png_get_color_type (png_ptr, info_ptr); GST_DEBUG ("PNG size %dx%d color_type %d", width, height, color_type); png_set_strip_16 (png_ptr); png_set_packing (png_ptr); if (color_type == PNG_COLOR_TYPE_RGB) { png_set_filler (png_ptr, 0xff, PNG_FILLER_BEFORE); } if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_set_swap_alpha (png_ptr); } frame_data = g_malloc (width * height * 4); frame = cog_frame_new_from_data_ARGB (frame_data, width, height); frame->regions[0] = frame_data; rows = (png_bytep *) g_malloc (sizeof (png_bytep) * height); for (j = 0; j < height; j++) { rows[j] = COG_FRAME_DATA_GET_LINE (frame->components + 0, j); } png_read_image (png_ptr, rows); g_free (rows); png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL); return frame; }
void write_header( const View& view ) { using png_rw_info_t = detail::png_write_support < typename channel_type<typename get_pixel_type<View>::type>::type, typename color_space_type<View>::type >; // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED png_set_IHDR( get_struct() , get_info() , static_cast< png_image_width::type >( view.width() ) , static_cast< png_image_height::type >( view.height() ) , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth ) , static_cast< png_color_type::type >( png_rw_info_t::_color_type ) , _info._interlace_method , _info._compression_type , _info._filter_method ); #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_cie_colors ) { png_set_cHRM( get_struct() , get_info() , _info._white_x , _info._white_y , _info._red_x , _info._red_y , _info._green_x , _info._green_y , _info._blue_x , _info._blue_y ); } if( _info._valid_file_gamma ) { png_set_gAMA( get_struct() , get_info() , _info._file_gamma ); } #else if( _info._valid_cie_colors ) { png_set_cHRM_fixed( get_struct() , get_info() , _info._white_x , _info._white_y , _info._red_x , _info._red_y , _info._green_x , _info._green_y , _info._blue_x , _info._blue_y ); } if( _info._valid_file_gamma ) { png_set_gAMA_fixed( get_struct() , get_info() , _info._file_gamma ); } #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_icc_profile ) { #if PNG_LIBPNG_VER_MINOR >= 5 png_set_iCCP( get_struct() , get_info() , const_cast< png_charp >( _info._icc_name.c_str() ) , _info._iccp_compression_type , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) ) , _info._profile_length ); #else png_set_iCCP( get_struct() , get_info() , const_cast< png_charp >( _info._icc_name.c_str() ) , _info._iccp_compression_type , const_cast< png_charp >( & (_info._profile.front()) ) , _info._profile_length ); #endif } if( _info._valid_intent ) { png_set_sRGB( get_struct() , get_info() , _info._intent ); } if( _info._valid_palette ) { png_set_PLTE( get_struct() , get_info() , const_cast< png_colorp >( &_info._palette.front() ) , _info._num_palette ); } if( _info._valid_background ) { png_set_bKGD( get_struct() , get_info() , const_cast< png_color_16p >( &_info._background ) ); } if( _info._valid_histogram ) { png_set_hIST( get_struct() , get_info() , const_cast< png_uint_16p >( &_info._histogram.front() ) ); } if( _info._valid_offset ) { png_set_oFFs( get_struct() , get_info() , _info._offset_x , _info._offset_y , _info._off_unit_type ); } if( _info._valid_pixel_calibration ) { std::vector< const char* > params( _info._num_params ); for( std::size_t i = 0; i < params.size(); ++i ) { params[i] = _info._params[ i ].c_str(); } png_set_pCAL( get_struct() , get_info() , const_cast< png_charp >( _info._purpose.c_str() ) , _info._X0 , _info._X1 , _info._cal_type , _info._num_params , const_cast< png_charp >( _info._units.c_str() ) , const_cast< png_charpp >( ¶ms.front() ) ); } if( _info._valid_resolution ) { png_set_pHYs( get_struct() , get_info() , _info._res_x , _info._res_y , _info._phy_unit_type ); } if( _info._valid_significant_bits ) { png_set_sBIT( get_struct() , get_info() , const_cast< png_color_8p >( &_info._sig_bits ) ); } #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_scale_factors ) { png_set_sCAL( get_struct() , get_info() , this->_info._scale_unit , this->_info._scale_width , this->_info._scale_height ); } #else #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED if( _info._valid_scale_factors ) { png_set_sCAL_fixed( get_struct() , get_info() , this->_info._scale_unit , this->_info._scale_width , this->_info._scale_height ); } #else if( _info._valid_scale_factors ) { png_set_sCAL_s( get_struct() , get_info() , this->_info._scale_unit , const_cast< png_charp >( this->_info._scale_width.c_str() ) , const_cast< png_charp >( this->_info._scale_height.c_str() ) ); } #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER if( _info._valid_text ) { std::vector< png_text > texts( _info._num_text ); for( std::size_t i = 0; i < texts.size(); ++i ) { png_text pt; pt.compression = _info._text[i]._compression; pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() ); pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() ); pt.text_length = _info._text[i]._text.length(); texts[i] = pt; } png_set_text( get_struct() , get_info() , &texts.front() , _info._num_text ); } if( _info._valid_modification_time ) { png_set_tIME( get_struct() , get_info() , const_cast< png_timep >( &_info._mod_time ) ); } if( _info._valid_transparency_factors ) { int sample_max = ( 1u << _info._bit_depth ); /* libpng doesn't reject a tRNS chunk with out-of-range samples */ if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY && (int) _info._trans_values[0].gray > sample_max ) || ( _info._color_type == PNG_COLOR_TYPE_RGB &&( (int) _info._trans_values[0].red > sample_max || (int) _info._trans_values[0].green > sample_max || (int) _info._trans_values[0].blue > sample_max ) ) ) ) { //@todo Fix that once reading transparency values works /* png_set_tRNS( get_struct() , get_info() , trans , num_trans , trans_values ); */ } } // Compression Levels - valid values are [0,9] png_set_compression_level( get_struct() , _info._compression_level ); png_set_compression_mem_level( get_struct() , _info._compression_mem_level ); png_set_compression_strategy( get_struct() , _info._compression_strategy ); png_set_compression_window_bits( get_struct() , _info._compression_window_bits ); png_set_compression_method( get_struct() , _info._compression_method ); png_set_compression_buffer_size( get_struct() , _info._compression_buffer_size ); #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED // Dithering if( _info._set_dithering ) { png_set_dither( get_struct() , &_info._dithering_palette.front() , _info._dithering_num_palette , _info._dithering_maximum_colors , &_info._dithering_histogram.front() , _info._full_dither ); } #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED // Filter if( _info._set_filter ) { png_set_filter( get_struct() , 0 , _info._filter ); } // Invert Mono if( _info._invert_mono ) { png_set_invert_mono( get_struct() ); } // True Bits if( _info._set_true_bits ) { png_set_sBIT( get_struct() , get_info() , &_info._true_bits.front() ); } // sRGB Intent if( _info._set_srgb_intent ) { png_set_sRGB( get_struct() , get_info() , _info._srgb_intent ); } // Strip Alpha if( _info._strip_alpha ) { png_set_strip_alpha( get_struct() ); } // Swap Alpha if( _info._swap_alpha ) { png_set_swap_alpha( get_struct() ); } png_write_info( get_struct() , get_info() ); }
bool MCImageDecodePNG(IO_handle p_stream, MCImageBitmap *&r_bitmap) { bool t_success = true; MCImageBitmap *t_bitmap = nil; png_structp t_png = nil; png_infop t_info = nil; png_infop t_end_info = nil; t_success = nil != (t_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); if (t_success) t_success = nil != (t_info = png_create_info_struct(t_png)); if (t_success) t_success = nil != (t_end_info = png_create_info_struct(t_png)); if (setjmp(png_jmpbuf(t_png))) { t_success = false; } if (t_success) { png_set_read_fn(t_png, p_stream, stream_read); png_read_info(t_png, t_info); } png_uint_32 t_width, t_height; int t_bit_depth, t_color_type; int t_interlace_method, t_compression_method, t_filter_method; int t_interlace_passes; if (t_success) { png_get_IHDR(t_png, t_info, &t_width, &t_height, &t_bit_depth, &t_color_type, &t_interlace_method, &t_compression_method, &t_filter_method); } if (t_success) t_success = MCImageBitmapCreate(t_width, t_height, t_bitmap); if (t_success) { bool t_need_alpha = false; t_interlace_passes = png_set_interlace_handling(t_png); if (t_color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(t_png); if (t_color_type == PNG_COLOR_TYPE_GRAY || t_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(t_png); if (png_get_valid(t_png, t_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(t_png); t_need_alpha = true; /* OVERHAUL - REVISIT - assume image has transparent pixels if tRNS is present */ t_bitmap->has_transparency = true; } if (t_color_type & PNG_COLOR_MASK_ALPHA) { t_need_alpha = true; /* OVERHAUL - REVISIT - assume image has alpha if color type allows it */ t_bitmap->has_alpha = t_bitmap->has_transparency = true; } else if (!t_need_alpha) png_set_add_alpha(t_png, 0xFF, MCswapbytes ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE); if (t_bit_depth == 16) png_set_strip_16(t_png); if (MCswapbytes) png_set_bgr(t_png); else png_set_swap_alpha(t_png); } // MW-2009-12-10: Support for color profiles MCColorTransformRef t_color_xform; t_color_xform = nil; // Try to get an embedded ICC profile... if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_iCCP)) { png_charp t_ccp_name; png_bytep t_ccp_profile; int t_ccp_compression_type; png_uint_32 t_ccp_profile_length; png_get_iCCP(t_png, t_info, &t_ccp_name, &t_ccp_compression_type, &t_ccp_profile, &t_ccp_profile_length); MCColorSpaceInfo t_csinfo; t_csinfo . type = kMCColorSpaceEmbedded; t_csinfo . embedded . data = t_ccp_profile; t_csinfo . embedded . data_size = t_ccp_profile_length; t_color_xform = MCscreen -> createcolortransform(t_csinfo); } // Next try an sRGB style profile... if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_sRGB)) { int t_intent; png_get_sRGB(t_png, t_info, &t_intent); MCColorSpaceInfo t_csinfo; t_csinfo . type = kMCColorSpaceStandardRGB; t_csinfo . standard . intent = (MCColorSpaceIntent)t_intent; t_color_xform = MCscreen -> createcolortransform(t_csinfo); } // Finally try for cHRM + gAMA... if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_cHRM) && png_get_valid(t_png, t_info, PNG_INFO_gAMA)) { MCColorSpaceInfo t_csinfo; t_csinfo . type = kMCColorSpaceCalibratedRGB; png_get_cHRM(t_png, t_info, &t_csinfo . calibrated . white_x, &t_csinfo . calibrated . white_y, &t_csinfo . calibrated . red_x, &t_csinfo . calibrated . red_y, &t_csinfo . calibrated . green_x, &t_csinfo . calibrated . green_y, &t_csinfo . calibrated . blue_x, &t_csinfo . calibrated . blue_y); png_get_gAMA(t_png, t_info, &t_csinfo . calibrated . gamma); t_color_xform = MCscreen -> createcolortransform(t_csinfo); } // Could not create any kind, so fallback to gamma transform. if (t_success && t_color_xform == nil) { double image_gamma; if (png_get_gAMA(t_png, t_info, &image_gamma)) png_set_gamma(t_png, MCgamma, image_gamma); else png_set_gamma(t_png, MCgamma, 0.45); } if (t_success) { for (uindex_t t_pass = 0; t_pass < t_interlace_passes; t_pass++) { png_bytep t_data_ptr = (png_bytep)t_bitmap->data; for (uindex_t i = 0; i < t_height; i++) { png_read_row(t_png, t_data_ptr, nil); t_data_ptr += t_bitmap->stride; } } } if (t_success) png_read_end(t_png, t_end_info); if (t_png != nil) png_destroy_read_struct(&t_png, &t_info, &t_end_info); // transform colours using extracted colour profile if (t_success && t_color_xform != nil) MCImageBitmapApplyColorTransform(t_bitmap, t_color_xform); if (t_color_xform != nil) MCscreen -> destroycolortransform(t_color_xform); if (t_success) r_bitmap = t_bitmap; else { if (t_bitmap != nil) MCImageFreeBitmap(t_bitmap); } return t_success; }
static void init_output(void) { int bit_depth ; int color_type ; int invert_mono = 0 ; png_colorp pngpalette = NULL ; png_bytep ptrans = NULL ; outfile = openout(flatspec.output_filename); libpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, my_error_callback, png_error_ptr_NULL); if( !libpng ) FatalUnexpected(_("Couldn't initialize libpng library")); libpng2 = png_create_info_struct(libpng); if( !libpng2 ) FatalUnexpected("Couldn't create PNG info structure"); png_init_io(libpng,outfile); bit_depth = 8; switch( flatspec.out_color_mode ) { case COLOR_GRAY: if( flatspec.default_pixel == PERHAPS_ALPHA_CHANNEL || flatspec.default_pixel == FORCE_ALPHA_CHANNEL ) color_type = PNG_COLOR_TYPE_GRAY_ALPHA ; else color_type = PNG_COLOR_TYPE_GRAY ; break ; case COLOR_RGB: if( flatspec.default_pixel == PERHAPS_ALPHA_CHANNEL || flatspec.default_pixel == FORCE_ALPHA_CHANNEL ) color_type = PNG_COLOR_TYPE_RGB_ALPHA ; else color_type = PNG_COLOR_TYPE_RGB ; break ; case COLOR_INDEXED: if( paletteSize == 2 && palette[0] == NEWALPHA(0,255) && palette[1] == NEWALPHA(-1,255) ) { color_type = PNG_COLOR_TYPE_GRAY ; bit_depth = 1 ; } else if( paletteSize == 2 && palette[0] == NEWALPHA(-1,255) && palette[1] == NEWALPHA(0,255) ) { color_type = PNG_COLOR_TYPE_GRAY ; bit_depth = 1 ; invert_mono = 1 ; } else { unsigned i ; int need_trans = flatspec.default_pixel == FORCE_ALPHA_CHANNEL ; color_type = PNG_COLOR_TYPE_PALETTE ; pngpalette = xcfmalloc(paletteSize*sizeof(png_color)) ; ptrans = xcfmalloc(paletteSize); for(i = 0; i<paletteSize; i++ ) { pngpalette[i].red = 255 & (palette[i] >> RED_SHIFT); pngpalette[i].green = 255 & (palette[i] >> GREEN_SHIFT); pngpalette[i].blue = 255 & (palette[i] >> BLUE_SHIFT); if( (ptrans[i] = ALPHA(palette[i])) != 255 ) need_trans = 1 ; } if( !need_trans ) { xcffree(ptrans); ptrans = NULL ; } if( paletteSize <= 2 ) bit_depth = 1 ; else if( paletteSize <= 4 ) bit_depth = 2 ; else if( paletteSize <= 16 ) bit_depth = 4 ; else bit_depth = 8; } break ; default: FatalUnexpected("This can't happen (unknown out_color_mode)"); } if( verboseFlag ) { fprintf(stderr,"Writing PNG: %s%s%s%s, %d bits", color_type & PNG_COLOR_MASK_COLOR ? _("color") : _("grayscale"), color_type & PNG_COLOR_MASK_PALETTE ? _("+palette") : "", color_type & PNG_COLOR_MASK_ALPHA ? _("+alpha") : "", ptrans || NULLALPHA(flatspec.default_pixel) ? _("+transparency") : "", bit_depth); if( pngpalette ) fprintf(stderr,_(" (%d colors)"),paletteSize); fprintf(stderr,"\n"); } png_set_IHDR(libpng,libpng2,flatspec.dim.width,flatspec.dim.height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if( invert_mono ) png_set_invert_mono(libpng); if( pngpalette ) png_set_PLTE(libpng,libpng2,pngpalette,paletteSize); if( ptrans ) png_set_tRNS(libpng,libpng2,ptrans,paletteSize,NULL); else if ( !pngpalette && NULLALPHA(flatspec.default_pixel) ) { static png_color_16 trans ; trans.gray = trans.red = 255 & (flatspec.default_pixel >> RED_SHIFT) ; trans.green = 255 & (flatspec.default_pixel >> GREEN_SHIFT) ; trans.blue = 255 & (flatspec.default_pixel >> BLUE_SHIFT) ; png_set_tRNS(libpng,libpng2,NULL,0,&trans); } /* png_set_text here */ png_write_info(libpng,libpng2); if( bit_depth < 8 ) png_set_packing(libpng); switch( color_type ) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGBA: #if (BLUE_SHIFT < RED_SHIFT) == !defined(WORDS_BIGENDIAN) png_set_bgr(libpng); #endif if( color_type == PNG_COLOR_TYPE_RGB ) #if (ALPHA_SHIFT < RED_SHIFT) == !defined(WORDS_BIGENDIAN) png_set_filler(libpng,0,PNG_FILLER_BEFORE); else png_set_swap_alpha(libpng); #else png_set_filler(libpng,0,PNG_FILLER_AFTER); #endif break ; case PNG_COLOR_TYPE_GRAY: png_set_filler(libpng,0,PNG_FILLER_AFTER); break ; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_PALETTE: break ; default: FatalUnexpected("This can't happen (unexpected png color_type)"); } }
static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0) { if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double file_gamma; png_get_gAMA(png_ptr, info_ptr, &file_gamma); png_set_gamma(png_ptr, screen_gamma, file_gamma); } png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; png_bytep trans_alpha = 0; png_color_16p trans_color_p = 0; int num_trans; png_colorp palette = 0; int num_palette; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) { image = QImage(width, height, QImage::Format_Mono); if (image.isNull()) return; } image.setColorCount(2); image.setColor(1, qRgb(0,0,0)); image.setColor(0, qRgb(255,255,255)); } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) { image = QImage(width, height, QImage::Format_ARGB32); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) { image = QImage(width, height, QImage::Format_Indexed8); if (image.isNull()) return; } image.setColorCount(ncols); for (int i=0; i<ncols; i++) { int c = i*255/(ncols-1); image.setColor(i, qRgba(c,c,c,0xff)); } if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { const int g = trans_color_p->gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) && num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); image.setColorCount(num_palette); int i = 0; if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { while (i < num_trans) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, trans_alpha[i] ) ); i++; } } while (i < num_palette) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, 0xff ) ); i++; } } else { // 32-bit if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); QImage::Format format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; } if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA) if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { png_set_bgr(png_ptr); } }
bool PNGImageFileType::write(const Image *OSG_PNG_ARG(pImage ), std::ostream &OSG_PNG_ARG(os ), const std::string &OSG_PNG_ARG(mimetype)) { #ifdef OSG_WITH_PNG png_structp png_ptr; png_infop info_ptr; if(pImage->getDimension() < 1 || pImage->getDimension() > 2) { FWARNING(("PNGImageFileType::write: invalid dimension %d!\n", pImage->getDimension())); return false; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, &errorOutput, &warningOutput); if(png_ptr == NULL) return false; /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return false; } /* set up the output handlers */ png_set_write_fn(png_ptr, &os, &osWriteFunc, &osFlushFunc); /* This is the hard way */ /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ Int32 ctype; switch(pImage->getPixelFormat()) { case Image::OSG_L_PF: ctype = PNG_COLOR_TYPE_GRAY; break; case Image::OSG_LA_PF: ctype = PNG_COLOR_TYPE_GRAY_ALPHA; break; #if defined(GL_BGR) || defined(GL_BGR_EXT) case Image::OSG_BGR_PF: #endif case Image::OSG_RGB_PF: ctype = PNG_COLOR_TYPE_RGB; break; #if defined(GL_BGRA) || defined(GL_BGRA_EXT) case Image::OSG_BGRA_PF: #endif case Image::OSG_RGBA_PF: ctype = PNG_COLOR_TYPE_RGB_ALPHA; break; default: FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n", pImage->getPixelFormat())); png_destroy_write_struct(&png_ptr, NULL); return false; } Int32 bit_depth; switch(pImage->getDataType()) { case Image::OSG_UINT8_IMAGEDATA: bit_depth = 8; break; case Image::OSG_UINT16_IMAGEDATA: bit_depth = 16; break; default: FWARNING (("Invalid pixeldepth, cannot store data\n")); return false; }; png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(), bit_depth,ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set resolution png supports only meter per pixel, // so we do a conversion from dpi with some rounding. png_uint_32 res_x = png_uint_32(pImage->getResX()); png_uint_32 res_y = png_uint_32(pImage->getResY()); if(pImage->getResUnit() == Image::OSG_RESUNIT_INCH) { res_x = png_uint_32((pImage->getResX() * 39.37007874f) < 0.0f ? (pImage->getResX() * 39.37007874f) - 0.5f : (pImage->getResX() * 39.37007874f) + 0.5f); res_y = png_uint_32((pImage->getResY() * 39.37007874f) < 0.0f ? (pImage->getResY() * 39.37007874f) - 0.5f : (pImage->getResY() * 39.37007874f) + 0.5f); } png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER); #if 0 /* optional significant bit chunk */ /* if we are dealing with a grayscale image then */ sig_bit.gray = true_bit_depth; /* otherwise, if we are dealing with a color image then */ sig_bit.red = true_red_bit_depth; sig_bit.green = true_green_bit_depth; sig_bit.blue = true_blue_bit_depth; /* if the image has an alpha channel then */ sig_bit.alpha = true_alpha_bit_depth; png_set_sBIT(png_ptr, info_ptr, sig_bit); /* Optional gamma chunk is strongly suggested if you have any guess * as to the correct gamma of the image. */ png_set_gAMA(png_ptr, info_ptr, gamma); /* Optionally write comments into the image */ text_ptr[0].key = "Title"; text_ptr[0].text = "Mona Lisa"; text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[1].key = "Author"; text_ptr[1].text = "Leonardo DaVinci"; text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[2].key = "Description"; text_ptr[2].text = "<long text>"; text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; #ifdef PNG_iTXt_SUPPORTED text_ptr[0].lang = NULL; text_ptr[1].lang = NULL; text_ptr[2].lang = NULL; #endif png_set_text(png_ptr, info_ptr, text_ptr, 3); #endif /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ /* note that if sRGB is present the gAMA and cHRM chunks must be ignored * on read and must be written in accordance with the sRGB profile */ /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap(png_ptr); #endif #if 0 /* invert monochrome pixels */ png_set_invert_mono(png_ptr); /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ png_set_shift(png_ptr, &sig_bit); /* pack pixels into bytes */ png_set_packing(png_ptr); /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels). The second parameter is not used. */ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); /* swap bytes of 16-bit files to most significant byte first */ png_set_swap(png_ptr); /* swap bits of 1, 2, 4 bit packed pixel formats */ png_set_packswap(png_ptr); #endif if(pImage->getPixelFormat() == Image::OSG_BGR_PF || pImage->getPixelFormat() == Image::OSG_BGRA_PF ) { /* flip BGR pixels to RGB */ png_set_bgr(png_ptr); /* swap location of alpha bytes from ARGB to RGBA */ png_set_swap_alpha(png_ptr); } /* The easiest way to write the image (you may have a different memory * layout, however, so choose what fits your needs best). You need to * use the first method if you aren't handling interlacing yourself. */ png_bytep *row_pointers = new png_bytep [pImage->getHeight()]; for(Int32 k = 0; k < pImage->getHeight(); k++) { row_pointers[k] = (const_cast<UInt8 *>(pImage->getData())) + (pImage->getHeight() - 1 - k) * pImage->getWidth() * pImage->getBpp(); } /* write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); /* clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); delete [] row_pointers; /* that's it */ return true; #else SWARNING << getMimeType() << " write is not compiled into the current binary " << endLog; return false; #endif }
bool KIPIWriteImage::write2PNG(const QString& destPath) { /* check this out for b/w support: http://lxr.kde.org/source/playground/graphics/krita-exp/kis_png_converter.cpp#607 */ QFile file(destPath); if (!file.open(QIODevice::ReadWrite)) { qDebug() << "Failed to open PNG file for writing" ; return false; } uchar* data = 0; int bitsDepth = d->sixteenBit ? 16 : 8; png_color_8 sig_bit; png_bytep row_ptr; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_ptr = png_create_info_struct(png_ptr); png_set_write_fn(png_ptr, (void*)&file, kipi_png_write_fn, kipi_png_flush_fn); if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) // Intel png_set_bgr(png_ptr); else // PPC png_set_swap_alpha(png_ptr); if (d->hasAlpha) { png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (d->sixteenBit) data = new uchar[d->width * 8 * sizeof(uchar)]; else data = new uchar[d->width * 4 * sizeof(uchar)]; } else { png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (d->sixteenBit) data = new uchar[d->width * 6 * sizeof(uchar)]; else data = new uchar[d->width * 3 * sizeof(uchar)]; } sig_bit.red = bitsDepth; sig_bit.green = bitsDepth; sig_bit.blue = bitsDepth; sig_bit.alpha = bitsDepth; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_set_compression_level(png_ptr, 9); // Write Software info. QString libpngver(QLatin1String(PNG_HEADER_VERSION_STRING)); libpngver.replace(QLatin1Char('\n'), QLatin1Char(' ')); QByteArray softAscii = libpngver.toLatin1(); png_text text; text.key = (png_charp)"Software"; text.text = softAscii.data(); text.compression = PNG_TEXT_COMPRESSION_zTXt; png_set_text(png_ptr, info_ptr, &(text), 1); png_write_info(png_ptr, info_ptr); png_set_shift(png_ptr, &sig_bit); png_set_packing(png_ptr); uchar* ptr = (uchar*)d->data.data(); uint x, y, j; for (y = 0; y < d->height; ++y) { if (cancel()) { delete [] data; file.close(); png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); return false; } j = 0; for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth()) { if (d->sixteenBit) { if (d->hasAlpha) { data[j++] = ptr[x+1]; // Blue data[j++] = ptr[ x ]; data[j++] = ptr[x+3]; // Green data[j++] = ptr[x+2]; data[j++] = ptr[x+5]; // Red data[j++] = ptr[x+4]; data[j++] = ptr[x+7]; // Alpha data[j++] = ptr[x+6]; } else { data[j++] = ptr[x+1]; // Blue data[j++] = ptr[ x ]; data[j++] = ptr[x+3]; // Green data[j++] = ptr[x+2]; data[j++] = ptr[x+5]; // Red data[j++] = ptr[x+4]; } } else { if (d->hasAlpha) { data[j++] = ptr[ x ]; // Blue data[j++] = ptr[x+1]; // Green data[j++] = ptr[x+2]; // Red data[j++] = ptr[x+3]; // Alpha } else { data[j++] = ptr[ x ]; // Blue data[j++] = ptr[x+1]; // Green data[j++] = ptr[x+2]; // Red } } } row_ptr = (png_bytep) data; png_write_rows(png_ptr, &row_ptr, 1); ptr += (d->width * bytesDepth()); } delete [] data; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); file.close(); return true; }
bool KPWriteImage::write2PNG(const QString& destPath) { FILE* file = fopen(QFile::encodeName(destPath), "wb"); if (!file) { kDebug( 51000 ) << "Failed to open PNG file for writing" << endl; return false; } uchar *data = 0; int bitsDepth = d->sixteenBit ? 16 : 8; png_color_8 sig_bit; png_bytep row_ptr; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, file); if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) // Intel png_set_bgr(png_ptr); else // PPC png_set_swap_alpha(png_ptr); if (d->hasAlpha) { png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (d->sixteenBit) data = new uchar[d->width * 8 * sizeof(uchar)]; else data = new uchar[d->width * 4 * sizeof(uchar)]; } else { png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (d->sixteenBit) data = new uchar[d->width * 6 * sizeof(uchar)]; else data = new uchar[d->width * 3 * sizeof(uchar)]; } sig_bit.red = bitsDepth; sig_bit.green = bitsDepth; sig_bit.blue = bitsDepth; sig_bit.alpha = bitsDepth; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_set_compression_level(png_ptr, 9); // Write ICC profil. if (!d->iccProfile.isEmpty()) { png_set_iCCP(png_ptr, info_ptr, (png_charp)"icc", PNG_COMPRESSION_TYPE_BASE, d->iccProfile.data(), d->iccProfile.size()); } // Write Software info. QString libpngver(PNG_HEADER_VERSION_STRING); libpngver.replace('\n', ' '); QString soft = d->kipipluginsVer; soft.append(QString(" (%1)").arg(libpngver)); png_text text; text.key = (png_charp)"Software"; text.text = soft.toAscii().data(); text.compression = PNG_TEXT_COMPRESSION_zTXt; png_set_text(png_ptr, info_ptr, &(text), 1); // Store Exif data. QByteArray ba = d->metadata.getExif(true); writeRawProfile(png_ptr, info_ptr, (png_charp)"exif", ba.data(), (png_uint_32) ba.size()); // Store Iptc data. QByteArray ba2 = d->metadata.getIptc(); writeRawProfile(png_ptr, info_ptr, (png_charp)"iptc", ba2.data(), (png_uint_32) ba2.size()); // Store Xmp data. QByteArray ba3 = d->metadata.getXmp(); writeRawProfile(png_ptr, info_ptr, (png_charp)("xmp"), ba3.data(), (png_uint_32) ba3.size()); png_write_info(png_ptr, info_ptr); png_set_shift(png_ptr, &sig_bit); png_set_packing(png_ptr); uchar* ptr = (uchar*)d->data.data(); uint x, y, j; for (y = 0; y < d->height; y++) { if (cancel()) { delete [] data; fclose(file); png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); return false; } j = 0; for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth()) { if (d->sixteenBit) { if (d->hasAlpha) { data[j++] = ptr[x+1]; // Blue data[j++] = ptr[ x ]; data[j++] = ptr[x+3]; // Green data[j++] = ptr[x+2]; data[j++] = ptr[x+5]; // Red data[j++] = ptr[x+4]; data[j++] = ptr[x+7]; // Alpha data[j++] = ptr[x+6]; } else { data[j++] = ptr[x+1]; // Blue data[j++] = ptr[ x ]; data[j++] = ptr[x+3]; // Green data[j++] = ptr[x+2]; data[j++] = ptr[x+5]; // Red data[j++] = ptr[x+4]; } } else { if (d->hasAlpha) { data[j++] = ptr[ x ]; // Blue data[j++] = ptr[x+1]; // Green data[j++] = ptr[x+2]; // Red data[j++] = ptr[x+3]; // Alpha } else { data[j++] = ptr[ x ]; // Blue data[j++] = ptr[x+1]; // Green data[j++] = ptr[x+2]; // Red } } } row_ptr = (png_bytep) data; png_write_rows(png_ptr, &row_ptr, 1); ptr += (d->width * bytesDepth()); } delete [] data; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); fclose(file); return true; }
void set_swap_alpha() const { TRACE_IO_TRANSFORM("png_set_swap_alpha\n"); png_set_swap_alpha(m_png); }
bool YImage::save( const char* fname, bool fast ) const { FILE* fp = NULL ; bool rval = true ; png_structp png_ptr = NULL ; png_infop info_ptr = NULL ; // Open the file for reading in binary mode. fp = fopen( fname, "wb" ) ; if( !fp ) { fprintf( stderr, ERROR_STRING_OPEN, fname ) ; rval = false ; goto YImage_save_cleanup ; } // Allocate the png structs. png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ) ; if( !png_ptr ) { fprintf( stderr, ERROR_STRING_WRITING, fname ) ; rval = false ; goto YImage_save_cleanup ; } info_ptr = png_create_info_struct( png_ptr ) ; if( !info_ptr ) { fprintf( stderr, ERROR_STRING_WRITING, fname ) ; rval = false ; goto YImage_save_cleanup ; } // Set up the png error routine. if( setjmp(png_jmpbuf(png_ptr)) ) { fprintf( stderr, ERROR_STRING_WRITING, fname ) ; rval = false ; goto YImage_save_cleanup ; } // Give libpng the FILE*. // png_init_io( png_ptr, fp ) ; // or // use our own write callback png_set_write_fn( png_ptr, fp, (png_rw_ptr) user_write_data, user_flush_data ) ; // We'll use the low-level interface since the high-level interface won't handle // png_set_filler() which we need to tell libpng to strip out the A from our // 4-byte pixels. // First we set and write the info struct. png_set_IHDR( png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ) ; png_write_info( png_ptr, info_ptr ) ; // If we've been asked to write quickly, speed up the compression. if( fast ) png_set_compression_level( png_ptr, Z_BEST_SPEED ); // Then we set up transforms. /* // 1. tell libpng to strip out the filler byte in our 4-byte pixels // if YPixel::a comes after any other member (b,g,r), we strip AFTER if( offsetof( YPixel, a ) > offsetof( YPixel, b ) ) { png_set_filler( png_ptr, 0, PNG_FILLER_AFTER ) ; // printf("alpha after\n"); } else { png_set_filler( png_ptr, 0, PNG_FILLER_BEFORE ) ; // printf("alpha before\n"); } */ if( offsetof( YPixel, a ) < offsetof( YPixel, b ) ) png_set_swap_alpha( png_ptr ) ; // 2. tell libpng how our color triples are stored (b < r or vice versa) if( offsetof( YPixel, b ) < offsetof( YPixel, r ) ) { png_set_bgr( png_ptr ) ; // printf("bgr\n") ; } // else { printf("rgb\n"); } // printf( "offsetof r, b: %d %d\n", offsetof( YPixel, r ), offsetof( YPixel, b ) ); // Finally we create a row_pointers[] pointing into our data* and write the png out to the FILE*. { // 1. allocate row pointers array png_bytep* row_pointers = (png_bytep*) png_malloc( png_ptr, m_height * sizeof(png_bytep) ) ; // 2. point row pointers into m_data for( int i = 0 ; i < m_height ; ++i ) { row_pointers[i] = (png_bytep) (m_data + i*m_width) ; } // 3. write the image data png_write_image( png_ptr, row_pointers ) ; // 4. free row pointers array png_free( png_ptr, row_pointers ) ; } // Write out end info. We're done. Fall through to cleanup. png_write_end( png_ptr, NULL ) ; YImage_save_cleanup: png_destroy_write_struct( png_ptr ? &png_ptr : NULL, info_ptr ? &info_ptr : NULL ) ; if( fp ) fclose( fp ) ; return rval ; }
bool YImage::load(const char* fname) { FILE* fp = NULL ; bool rval = true; png_structp png_ptr = NULL ; png_infop info_ptr = NULL ; // for checking the png header const size_t PNG_BYTES_TO_CHECK = 4 ; // example.c uses 4 png_byte header[ PNG_BYTES_TO_CHECK ] ; // Open the file for reading in binary mode. fp = fopen( fname, "rb" ) ; if( !fp ) { fprintf( stderr, ERROR_STRING_OPEN, fname ) ; rval = false; goto YImage_load_cleanup ; } // Check some bytes at the beginning of the file to make sure it's a png. if( PNG_BYTES_TO_CHECK != fread( header, 1, PNG_BYTES_TO_CHECK, fp ) ) { fprintf( stderr, ERROR_STRING_INVALID_FILE, fname ) ; rval = false; goto YImage_load_cleanup ; } if( png_sig_cmp( header, 0, PNG_BYTES_TO_CHECK ) ) { fprintf( stderr, ERROR_STRING_INVALID_FILE, fname ) ; rval = false; goto YImage_load_cleanup ; } // Since it looks like we have a good png file, allocate the png structs. png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ) ; if( !png_ptr ) { fprintf( stderr, ERROR_STRING_LIBERR ) ; rval = false; goto YImage_load_cleanup ; } info_ptr = png_create_info_struct( png_ptr ) ; if( !info_ptr ) { fprintf( stderr, ERROR_STRING_LIBERR ) ; rval = false; goto YImage_load_cleanup ; } // Set up the png error routine. if( setjmp(png_jmpbuf(png_ptr)) ) { fprintf( stderr, ERROR_STRING_MAYBE_FILE, fname ) ; rval = false; goto YImage_load_cleanup ; } // Give libpng the FILE*, tell it how many bytes we read. // png_init_io( png_ptr, fp ) ; // or // use our own read callback png_set_read_fn( png_ptr, fp, (png_rw_ptr) user_read_data ) ; png_set_sig_bytes( png_ptr, PNG_BYTES_TO_CHECK ) ; // We'll use the low-level interface since the high-level interface won't handle // png_set_filler() which we need to guarantee there'll be a filler "A" in our // 4-byte ARGB pixels. // Really the low-level interface isn't more complicated than the high-level interface. // To choose transform flags we have to query the png_info struct. // Instead of OR'ing in another transform flag (high-level interface), we call a set // method (low-level interface). // First we read the info struct. png_read_info( png_ptr, info_ptr ) ; // Now we set up transforms. // 1. convert gray and paletted to rgb (this guarantees 8 or 16 bit depths (rgb must be 8 or 16)). // also expand the alpha color to an alpha channel and convert 16 bit depths to 8. // 2. if we don't have alpha, add an opaque channel. also swap RGB and BGR depending on YPixel. // 3. ask libpng to deinterlace { png_byte color_type = png_get_color_type( png_ptr, info_ptr ) ; png_byte depth = png_get_bit_depth( png_ptr, info_ptr ) ; // 1 if( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_expand( png_ptr ) ; if( color_type == PNG_COLOR_TYPE_GRAY && depth < 8 ) png_set_expand( png_ptr ) ; if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_set_expand( png_ptr ) ; if( depth == 16 ) png_set_strip_16( png_ptr ) ; if( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png_ptr ) ; // NOTE: This next step affects the layout of the channels in the pixel. // We turn the pixel into the format in YPixel, // with the restrication that alpha comes at the beginning or end // and green is sandwiched between red and blue. // The possibilities are: ARGB, ABGR, RGBA, BGRA. // 2 if( color_type != PNG_COLOR_TYPE_GRAY_ALPHA && color_type != PNG_COLOR_TYPE_RGB_ALPHA && !png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_set_filler( png_ptr, 0xFF, offsetof( YPixel, a ) < offsetof( YPixel, b ) ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER ) ; else if( offsetof( YPixel, a ) < offsetof( YPixel, b ) ) png_set_swap_alpha( png_ptr ) ; if( offsetof( YPixel, b ) < offsetof( YPixel, r ) ) png_set_bgr( png_ptr ) ; // 3 png_set_interlace_handling( png_ptr ) ; } // We're almost ready to copy over the png data. // First we must resize our data* and set our width & height. { png_uint_32 widthh = png_get_image_width( png_ptr, info_ptr ) ; png_uint_32 heightt = png_get_image_height( png_ptr, info_ptr ) ; // fprintf( stderr, "width: %d, height: %d\n", (int) widthh, (int) heightt ) ; resize( widthh, heightt ) ; } // Now we can create a rows[] pointing into our data* and read the png into our buffer. { // fprintf( stderr, "width: %d, height: %d\n", (int) m_width, (int) m_height ) ; /* png_byte channels = png_get_channels( png_ptr, info_ptr ) ; assert( 4 == channels ) ; png_byte depth = png_get_bit_depth( png_ptr, info_ptr ) ; assert( 8 == depth ) ; png_uint_32 rowbytes = png_get_rowbytes( png_ptr, info_ptr ) ; assert( sizeof(YPixel) * m_width == rowbytes ) ; */ // 1. allocate row pointers array png_bytep* row_pointers = (png_bytep*) png_malloc( png_ptr, m_height * sizeof(png_bytep) ) ; // 2. point row pointers into m_data for( int i = 0 ; i < m_height ; ++i ) row_pointers[i] = (png_bytep) (m_data + i*m_width ) ; // 3. read the image data png_read_image( png_ptr, row_pointers ) ; // 4. free row pointers array png_free( png_ptr, row_pointers ) ; } // Read the end info. We're done. Fall through to cleanup. png_read_end( png_ptr, NULL ) ; YImage_load_cleanup: // due to (what looks like) a bug in libpng-1.2.4, we can't pass NULL for the png_ptr arg if( png_ptr ) png_destroy_read_struct( &png_ptr, info_ptr ? &info_ptr : NULL, NULL ) ; if( fp ) fclose( fp ) ; return rval ; }
void PNGAPI png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms, voidp params) { int row; if(png_ptr == NULL) return; #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif png_read_info(png_ptr, info_ptr); if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) png_error(png_ptr,"Image is too high to process with png_read_png()"); #if defined(PNG_READ_16_TO_8_SUPPORTED) if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); #endif #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif #if defined(PNG_READ_EXPAND_SUPPORTED) if (transforms & PNG_TRANSFORM_EXPAND) if ((png_ptr->bit_depth < 8) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); #endif #if defined(PNG_READ_INVERT_SUPPORTED) if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) if ((transforms & PNG_TRANSFORM_SHIFT) && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } #endif #if defined(PNG_READ_BGR_SUPPORTED) if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #if defined(PNG_READ_SWAP_SUPPORTED) if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif png_read_update_info(png_ptr, info_ptr); #ifdef PNG_FREE_ME_SUPPORTED png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); #endif if(info_ptr->row_pointers == NULL) { info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, info_ptr->height * png_sizeof(png_bytep)); #ifdef PNG_FREE_ME_SUPPORTED info_ptr->free_me |= PNG_FREE_ROWS; #endif for (row = 0; row < (int)info_ptr->height; row++) { info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } } png_read_image(png_ptr, info_ptr->row_pointers); info_ptr->valid |= PNG_INFO_IDAT; png_read_end(png_ptr, info_ptr); transforms = transforms; params = params; }
s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, PExtInParam extra_in_param = vm::null, PExtOutParam extra_out_param = vm::null) { if (in_param->outputPackFlag == CELL_PNGDEC_1BYTE_PER_NPIXEL) { fmt::throw_exception("Packing not supported! (%d)" HERE, in_param->outputPackFlag); } // flag to keep unknown chunks png_set_keep_unknown_chunks(stream->png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 0, 0); // Scale 16 bit depth down to 8 bit depth. if (stream->info.bitDepth == 16 && in_param->outputBitDepth == 8) { // PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then. png_set_strip_16(stream->png_ptr); } // This shouldnt ever happen, but not sure what to do if it does, just want it logged for now if (stream->info.bitDepth != 16 && in_param->outputBitDepth == 16) cellPngDec.error("Output depth of 16 with non input depth of 16 specified!"); if (in_param->commandPtr != vm::null) cellPngDec.warning("Ignoring CommandPtr."); if (stream->info.colorSpace != in_param->outputColorSpace) { // check if we need to set alpha const bool inputHasAlpha = cellPngColorSpaceHasAlpha(stream->info.colorSpace); const bool outputWantsAlpha = cellPngColorSpaceHasAlpha(in_param->outputColorSpace); if (outputWantsAlpha && !inputHasAlpha) { if (in_param->outputAlphaSelect == CELL_PNGDEC_FIX_ALPHA) png_set_add_alpha(stream->png_ptr, in_param->outputColorAlpha, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); else { // Check if we can steal the alpha from a trns block if (png_get_valid(stream->png_ptr, stream->info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(stream->png_ptr); // if not, just set default of 0xff else png_set_add_alpha(stream->png_ptr, 0xff, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); } } else if (inputHasAlpha && !outputWantsAlpha) png_set_strip_alpha(stream->png_ptr); else if (in_param->outputColorSpace == CELL_PNGDEC_ARGB && stream->info.colorSpace == CELL_PNGDEC_RGBA) png_set_swap_alpha(stream->png_ptr); // Handle gray<->rgb colorspace conversions // rgb output if (in_param->outputColorSpace == CELL_PNGDEC_ARGB || in_param->outputColorSpace == CELL_PNGDEC_RGBA || in_param->outputColorSpace == CELL_PNGDEC_RGB) { if (stream->info.colorSpace == CELL_PNGDEC_PALETTE) png_set_palette_to_rgb(stream->png_ptr); if ((stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE || stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA) && stream->info.bitDepth < 8) png_set_expand_gray_1_2_4_to_8(stream->png_ptr); } // grayscale output else { if (stream->info.colorSpace == CELL_PNGDEC_ARGB || stream->info.colorSpace == CELL_PNGDEC_RGBA || stream->info.colorSpace == CELL_PNGDEC_RGB) { png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); } else { // not sure what to do here cellPngDec.error("Grayscale / Palette to Grayscale / Palette conversion currently unsupported."); } } } stream->passes = png_set_interlace_handling(stream->png_ptr); // Update the info structure png_read_update_info(stream->png_ptr, stream->info_ptr); stream->out_param.outputWidth = stream->info.imageWidth; stream->out_param.outputHeight = stream->info.imageHeight; stream->out_param.outputBitDepth = in_param->outputBitDepth; stream->out_param.outputColorSpace = in_param->outputColorSpace; stream->out_param.outputMode = in_param->outputMode; stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr); stream->out_param.outputComponents = png_get_channels(stream->png_ptr, stream->info_ptr); stream->packing = in_param->outputPackFlag; // Set the memory usage. We currently don't actually allocate memory for libpng through the callbacks, due to libpng needing a lot more memory compared to PS3 variant. stream->out_param.useMemorySpace = 0; if (extra_in_param) { if (extra_in_param->bufferMode != CELL_PNGDEC_LINE_MODE) { cellPngDec.error("Invalid Buffermode specified."); return CELL_PNGDEC_ERROR_ARG; } if (stream->passes > 1) { stream->outputCounts = 1; } else stream->outputCounts = extra_in_param->outputCounts; if (extra_out_param) { if (stream->outputCounts == 0) extra_out_param->outputHeight = stream->out_param.outputHeight; else extra_out_param->outputHeight = std::min(stream->outputCounts, stream->out_param.outputHeight.value()); extra_out_param->outputWidthByte = stream->out_param.outputWidthByte; } } *out_param = stream->out_param; return CELL_OK; }
/* pngReadImage: Reads an image from a memory buffer. Returns: non-zero if successful. */ int pngReadImage(int w, int h, int d, char* bits, char *data, int nBytes) { png_bytep *row_pointers = NULL; pngReadState rs; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; DBG("pngReadImage: png_sig_cmp"); /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. */ if(png_sig_cmp(data, (png_size_t)0, PNG_BYTES_TO_CHECK)) return 0; DBG("pngReadImage: png_create_read_struct"); /* Create the png_struct */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) return 0; DBG("pngReadImage: png_create_info_struct"); /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); return 0; } /* Set error handling. REQUIRED if you aren't supplying your own * error handling functions in the png_create_read_struct() call. */ if (setjmp(png_jmpbuf(png_ptr))) { DBG("pngReadImage: triggered png_error"); /* If we get here, we had a problem reading the file */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); if(row_pointers) free(row_pointers); return 0; } rs.data = data; rs.position = 0; rs.length = nBytes; png_set_read_fn(png_ptr, (void *)&rs, readBytes); DBG("pngReadImage: png_read_info"); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* Set up the data transformations you want. Note that these are all * optional. Only call them if you want/need them. Many of the * transformations only work on specific types of images, and many * are mutually exclusive. */ /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) { DBG("pngReadImage: png_set_bgr"); png_set_bgr(png_ptr); } if(d == 32 && color_type == PNG_COLOR_TYPE_RGB) { /* Add filler (or alpha) byte (before/after each RGB triplet) */ DBG("pngReadImage: png_set_filler"); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } if(0) { /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); } /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if(0) { /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } if(0) { /* Tell libpng to handle the gamma conversion for you. The final call * is a good guess for PC generated images, but it should be configurable * by the user at run time by the user. It is strongly suggested that * your application support gamma correction. */ int intent; double screen_gamma = 1.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); } } if(0) { /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } } if(0) { /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ png_set_swap_alpha(png_ptr); /* swap bytes of 16 bit files to least significant byte first */ png_set_swap(png_ptr); } { /* initialize the png row pointers */ int row, ppw = 32 / d; int pitch = ((w + ppw - 1) / ppw) * 4; int rowbytes = png_get_rowbytes(png_ptr, info_ptr); if(0) { char info[100]; sprintf(info, "Form pitch: %d\nPNG rowbytes: %d",pitch, rowbytes); DBG(info); } /* XXXX: It seems that this test is pretty pointless; PNG appears to return the raw rowbytes value, not the padded one. A better test is probably to compare the w/h/d values of png with the form values to ensure correctness. */ if(pitch < rowbytes) { png_error(png_ptr, "Row bytes mismatch"); } row_pointers = (png_bytep*) calloc(h, sizeof(void*)); for (row = 0; row < h; row++) { row_pointers[row] = bits + (row*pitch); } } DBG("pngReadImage: png_read_image"); /* Read the entire image in one go */ png_read_image(png_ptr, row_pointers); DBG("pngReadImage: Cleaning up"); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); if(row_pointers) free(row_pointers); return 1; }
ImageNode *LoadPNGImage(const char *fileName, int rwidth, int rheight, char preserveAspect) { static ImageNode *result; static FILE *fd; static unsigned char **rows; static png_structp pngData; static png_infop pngInfo; static png_infop pngEndInfo; unsigned char header[8]; unsigned long rowBytes; int bitDepth, colorType; unsigned int x, y; png_uint_32 width; png_uint_32 height; Assert(fileName); result = NULL; fd = NULL; rows = NULL; pngData = NULL; pngInfo = NULL; pngEndInfo = NULL; fd = fopen(fileName, "rb"); if(!fd) { return NULL; } x = fread(header, 1, sizeof(header), fd); if(x != sizeof(header) || png_sig_cmp(header, 0, sizeof(header))) { fclose(fd); return NULL; } pngData = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(JUNLIKELY(!pngData)) { fclose(fd); Warning(_("could not create read struct for PNG image: %s"), fileName); return NULL; } if(JUNLIKELY(setjmp(png_jmpbuf(pngData)))) { png_destroy_read_struct(&pngData, &pngInfo, &pngEndInfo); if(fd) { fclose(fd); } if(rows) { ReleaseStack(rows); } DestroyImage(result); Warning(_("error reading PNG image: %s"), fileName); return NULL; } pngInfo = png_create_info_struct(pngData); if(JUNLIKELY(!pngInfo)) { png_destroy_read_struct(&pngData, NULL, NULL); fclose(fd); Warning(_("could not create info struct for PNG image: %s"), fileName); return NULL; } pngEndInfo = png_create_info_struct(pngData); if(JUNLIKELY(!pngEndInfo)) { png_destroy_read_struct(&pngData, &pngInfo, NULL); fclose(fd); Warning("could not create end info struct for PNG image: %s", fileName); return NULL; } png_init_io(pngData, fd); png_set_sig_bytes(pngData, sizeof(header)); png_read_info(pngData, pngInfo); png_get_IHDR(pngData, pngInfo, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); result = CreateImage(width, height, 0); png_set_expand(pngData); if(bitDepth == 16) { png_set_strip_16(pngData); } else if(bitDepth < 8) { png_set_packing(pngData); } png_set_swap_alpha(pngData); png_set_filler(pngData, 0xFF, PNG_FILLER_BEFORE); if(colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(pngData); } png_read_update_info(pngData, pngInfo); rowBytes = png_get_rowbytes(pngData, pngInfo); rows = AllocateStack(result->height * sizeof(result->data)); y = 0; for(x = 0; x < result->height; x++) { rows[x] = &result->data[y]; y += rowBytes; } png_read_image(pngData, rows); png_read_end(pngData, pngInfo); png_destroy_read_struct(&pngData, &pngInfo, &pngEndInfo); fclose(fd); ReleaseStack(rows); rows = NULL; return result; }
LICE_IBitmap *LICE_LoadPNG(const char *filename, LICE_IBitmap *bmp) { FILE *fp = NULL; #if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8) #ifdef WDL_SUPPORT_WIN9X if (GetVersion()<0x80000000) #endif { WCHAR wf[2048]; if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048)) fp = _wfopen(wf,L"rb"); } #endif if (!fp) fp = fopen(filename,"rb"); if (!fp) return 0; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { fclose(fp); return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return 0; } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); unsigned int width, height; int bit_depth, color_type, interlace_type, compression_type, filter_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); //convert whatever it is to RGBA if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); 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 (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (color_type & PNG_COLOR_MASK_ALPHA) png_set_swap_alpha(png_ptr); else png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); LICE_IBitmap *delbmp = NULL; if (bmp) bmp->resize(width,height); else delbmp = bmp = new WDL_NEW LICE_MemBitmap(width,height); if (!bmp || bmp->getWidth() != (int)width || bmp->getHeight() != (int)height) { delete delbmp; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return 0; } unsigned char **row_pointers=(unsigned char **)malloc(height*sizeof(unsigned char *));; LICE_pixel *srcptr = bmp->getBits(); int dsrcptr=bmp->getRowSpan(); if (bmp->isFlipped()) { srcptr += dsrcptr*(bmp->getHeight()-1); dsrcptr=-dsrcptr; } unsigned int i; for(i=0;i<height;i++) { row_pointers[i]=(unsigned char *)srcptr; srcptr+=dsrcptr; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); #if !(LICE_PIXEL_A == 0 && LICE_PIXEL_R == 1 && LICE_PIXEL_G == 2 && LICE_PIXEL_B == 3) for(i=0;i<height;i++) { unsigned char *bp = row_pointers[i]; int j=width; while (j-->0) { unsigned char a = bp[0]; unsigned char r = bp[1]; unsigned char g = bp[2]; unsigned char b = bp[3]; ((LICE_pixel*)bp)[0] = LICE_RGBA(r,g,b,a); bp+=4; } } #endif free(row_pointers); return bmp; }
/** Our implementation of libPNG callbacks */ void haveInfo() { int bitDepth, colorType, interlaceType; png_get_IHDR(pngReadStruct, pngInfoStruct, &width, &height, &bitDepth, &colorType, &interlaceType, 0, 0); if (!ImageManager::isAcceptableSize(width, height)) { libPngError = true; return; } //Ask libPNG to change bit depths we don't support if (bitDepth < 8) #if PNG_LIBPNG_VER < 10400 png_set_gray_1_2_4_to_8(pngReadStruct); #else png_set_expand_gray_1_2_4_to_8(pngReadStruct); #endif if (bitDepth > 8) png_set_strip_16 (pngReadStruct); //Some images (basically, only paletted ones) may have alpha //included as part of a tRNS chunk. We want to convert that to regular alpha //channel.. bool haveTRNS = false; if (png_get_valid(pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngReadStruct); haveTRNS = true; if (colorType == PNG_COLOR_TYPE_RGB) colorType = PNG_COLOR_TYPE_RGB_ALPHA; //Paranoia.. else if (colorType == PNG_COLOR_TYPE_GRAY) colorType = PNG_COLOR_TYPE_GRAY_ALPHA; } ImageFormat imFrm; //Prepare for mapping from colorType to our format descriptors. switch (colorType) { case PNG_COLOR_TYPE_GRAY: imFrm.greyscaleSetup(); break; case PNG_COLOR_TYPE_GRAY_ALPHA: //We don't natively support 8-bit plus alpha, so ask libPNG to expand it out to RGB png_set_gray_to_rgb(pngReadStruct); imFrm.type = ImageFormat::Image_ARGB_32; break; case PNG_COLOR_TYPE_PALETTE: //For now, we handle paletted images as RGB or ARGB //### TODO: handle non-alpha paletted images with a sufficiently small palette as //paletted imFrm.type = haveTRNS ? ImageFormat::Image_ARGB_32 : ImageFormat::Image_RGB_32; png_set_palette_to_rgb(pngReadStruct); break; case PNG_COLOR_TYPE_RGB: imFrm.type = ImageFormat::Image_RGB_32; break; case PNG_COLOR_TYPE_RGB_ALPHA: imFrm.type = ImageFormat::Image_ARGB_32; break; default: //Huh? libPngError = true; return; } //Configure padding/byte swapping if need be (32-bit images) //We want a 32-bit value with ARGB. //This means that for little-endian, in memory we should have BGRA, //and for big-endian, well, ARGB if (imFrm.type == ImageFormat::Image_RGB_32) { //Need fillers, plus perhaps BGR swapping for non-alpha #if Q_BYTE_ORDER == Q_BIG_ENDIAN || defined(__BIG_ENDIAN__) png_set_filler(pngReadStruct, 0xff, PNG_FILLER_BEFORE); #else png_set_filler(pngReadStruct, 0xff, PNG_FILLER_AFTER); png_set_bgr (pngReadStruct); #endif } else if (imFrm.type == ImageFormat::Image_ARGB_32) { #if Q_BYTE_ORDER == Q_BIG_ENDIAN || defined(__BIG_ENDIAN__) png_set_swap_alpha(pngReadStruct); //ARGB, not RGBA #else png_set_bgr (pngReadStruct); //BGRA #endif } //Remember depth, for our own use depth = imFrm.depth(); //handle interlacing if (interlaceType != PNG_INTERLACE_NONE) { interlaced = true; scanlineBuf = new unsigned char[depth * width]; png_set_interlace_handling(pngReadStruct); // Give up on premultiply in this case.. if (imFrm.type == ImageFormat::Image_ARGB_32) imFrm.type = ImageFormat::Image_ARGB_32_DontPremult; } notifySingleFrameImage(width, height, imFrm); //OK, time to start input png_read_update_info(pngReadStruct, pngInfoStruct); }
LICE_IBitmap *LICE_LoadPNGFromMemory(const void *data_in, int buflen, LICE_IBitmap *bmp) { if (buflen<8) return NULL; unsigned char *data = (unsigned char *)(void*)data_in; if(png_sig_cmp(data, 0, 8)) return NULL; pngReadStruct readStruct = {data, buflen}; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } png_set_read_fn(png_ptr, &readStruct, staticPngReadFunc); png_read_info(png_ptr, info_ptr); unsigned int width, height; int bit_depth, color_type, interlace_type, compression_type, filter_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); //convert whatever it is to RGBA if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); 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 (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (color_type & PNG_COLOR_MASK_ALPHA) png_set_swap_alpha(png_ptr); else png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); LICE_IBitmap *delbmp = NULL; if (bmp) bmp->resize(width,height); else delbmp = bmp = new WDL_NEW LICE_MemBitmap(width,height); if (!bmp || bmp->getWidth() != (int)width || bmp->getHeight() != (int)height) { delete delbmp; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return 0; } unsigned char **row_pointers=(unsigned char **)malloc(height*sizeof(unsigned char *));; LICE_pixel *srcptr = bmp->getBits(); int dsrcptr=bmp->getRowSpan(); unsigned int i; for(i=0;i<height;i++) { row_pointers[i]=(unsigned char *)srcptr; srcptr+=dsrcptr; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); //put shit in correct order #if !(LICE_PIXEL_A == 0 && LICE_PIXEL_R == 1 && LICE_PIXEL_G == 2 && LICE_PIXEL_B == 3) for(i=0;i<height;i++) { unsigned char *bp = row_pointers[i]; int j=width; while (j-->0) { unsigned char a = bp[0]; unsigned char r = bp[1]; unsigned char g = bp[2]; unsigned char b = bp[3]; ((LICE_pixel*)bp)[0] = LICE_RGBA(r,g,b,a); bp+=4; } } #endif free(row_pointers); return bmp; }
UInt64 PNGImageFileType::storeData(const Image *OSG_PNG_ARG (pImage ), UChar8 *OSG_PNG_ARG (buffer ), Int32 OSG_CHECK_ARG(memSize)) { #ifdef OSG_WITH_PNG png_structp png_ptr; png_infop info_ptr; if(pImage->getDimension() < 1 || pImage->getDimension() > 2) { FWARNING(("PNGImageFileType::write: invalid dimension %d!\n", pImage->getDimension())); return 0; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, &errorOutput, &warningOutput); if (png_ptr == NULL) { return 0; } /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return 0; } BufferInfo bufferInfo; bufferInfo.buffer = buffer; bufferInfo.length = 0; png_set_write_fn(png_ptr, static_cast<void *>(&bufferInfo), user_write_data, user_flush_data); /* This is the hard way */ /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ Int32 ctype; switch(pImage->getPixelFormat()) { case Image::OSG_L_PF: ctype = PNG_COLOR_TYPE_GRAY; break; case Image::OSG_LA_PF: ctype = PNG_COLOR_TYPE_GRAY_ALPHA; break; #if defined(GL_BGR) || defined(GL_BGR_EXT) case Image::OSG_BGR_PF: #endif case Image::OSG_RGB_PF: ctype = PNG_COLOR_TYPE_RGB; break; #if defined(GL_BGRA) || defined(GL_BGRA_EXT) case Image::OSG_BGRA_PF: #endif case Image::OSG_RGBA_PF: ctype = PNG_COLOR_TYPE_RGB_ALPHA; break; default: FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n", pImage->getPixelFormat())); png_destroy_write_struct(&png_ptr, NULL); return 0; } Int32 bit_depth; switch (pImage->getDataType()) { case Image::OSG_UINT8_IMAGEDATA: bit_depth = 8; break; case Image::OSG_UINT16_IMAGEDATA: bit_depth = 16; break; default: FWARNING (("Invalid pixeldepth, cannot store data\n")); return 0; }; png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(), bit_depth, ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ /* note that if sRGB is present the gAMA and cHRM chunks must be ignored * on read and must be written in accordance with the sRGB profile */ /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap(png_ptr); #endif if(pImage->getPixelFormat() == Image::OSG_BGR_PF || pImage->getPixelFormat() == Image::OSG_BGRA_PF) { /* flip BGR pixels to RGB */ png_set_bgr(png_ptr); /* swap location of alpha bytes from ARGB to RGBA */ png_set_swap_alpha(png_ptr); } /* The easiest way to write the image (you may have a different memory * layout, however, so choose what fits your needs best). You need to * use the first method if you aren't handling interlacing yourself. */ png_bytep *row_pointers = new png_bytep [pImage->getHeight()]; for(Int32 k = 0; k < pImage->getHeight(); k++) { row_pointers[k] = (const_cast<UInt8 *>(pImage->getData())) + (pImage->getHeight() - 1 - k) * pImage->getWidth() * pImage->getBpp(); } /* write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); /* clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); delete [] row_pointers; /* that's it */ return bufferInfo.length; #else SWARNING << getMimeType() << " storeData is not compiled into the current binary " << std::endl; return 0; #endif }
// load in the image data IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const { #ifdef _IRR_COMPILE_WITH_LIBPNG_ if (!file) return 0; video::IImage* image = 0; //Used to point to image rows u8** RowPointers = 0; png_byte buffer[8]; // Read the first few bytes of the PNG file if( file->read(buffer, 8) != 8 ) { os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR); return 0; } // Check if it really is a PNG file if( png_sig_cmp(buffer, 0, 8) ) { os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR); return 0; } // Allocate the png read struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)png_cpexcept_error, NULL); if (!png_ptr) { os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR); return 0; } // Allocate the png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { os::Printer::log("LOAD PNG: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // for proper error handling if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (RowPointers) delete [] RowPointers; return 0; } // 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 u32 Width; u32 Height; s32 BitDepth; s32 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_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); // Update the changes png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&Width, (png_uint_32*)&Height, &BitDepth, &ColorType, NULL, NULL, NULL); // Convert RGBA to BGRA if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) { #ifdef __BIG_ENDIAN__ png_set_swap_alpha(png_ptr); #else png_set_bgr(png_ptr); #endif } // Update the changes png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&Width, (png_uint_32*)&Height, &BitDepth, &ColorType, NULL, NULL, NULL); // Create the image structure to be filled by png data if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) image = new CImage(ECF_A8R8G8B8, core::dimension2d<s32>(Width, Height)); else image = new CImage(ECF_R8G8B8, core::dimension2d<s32>(Width, Height)); if (!image) { os::Printer::log("LOAD PNG: Internal PNG create image struct failure\n", file->getFileName(), ELL_ERROR); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // Create array of pointers to rows in image data RowPointers = new png_bytep[Height]; if (!RowPointers) { os::Printer::log("LOAD PNG: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR); png_destroy_read_struct(&png_ptr, NULL, NULL); delete image; return 0; } // Fill array of pointers to rows in image data unsigned char* data = (unsigned char*)image->lock(); for (u32 i=0; i<Height; ++i) { RowPointers[i]=data; data += image->getPitch(); } // for proper error handling if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete [] RowPointers; image->unlock(); delete [] image; return 0; } // Read data using the library function that handles all transformations including interlacing png_read_image(png_ptr, RowPointers); png_read_end(png_ptr, NULL); delete [] RowPointers; image->unlock(); png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory return image; #else return 0; #endif // _IRR_COMPILE_WITH_LIBPNG_ }
static void setup_qt( QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0 ) { if ( screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) ) { double file_gamma; png_get_gAMA(png_ptr, info_ptr, &file_gamma); png_set_gamma( png_ptr, screen_gamma, file_gamma ); } png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if ( color_type == PNG_COLOR_TYPE_GRAY ) { // Black & White or 8-bit grayscale if ( bit_depth == 1 && info_ptr->channels == 1 ) { png_set_invert_mono( png_ptr ); png_read_update_info( png_ptr, info_ptr ); if (!image.create( width, height, 1, 2, QImage::BigEndian )) return; image.setColor( 1, qRgb(0,0,0) ); image.setColor( 0, qRgb(255,255,255) ); } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (!image.create(width, height, 32)) return; image.setAlphaBuffer(TRUE); if (QImage::systemByteOrder() == QImage::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } else { if ( bit_depth == 16 ) png_set_strip_16(png_ptr); else if ( bit_depth < 8 ) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); if (!image.create(width, height, 8, ncols)) return; for (int i=0; i<ncols; i++) { int c = i*255/(ncols-1); image.setColor( i, qRgba(c,c,c,0xff) ); } if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ) { const int g = info_ptr->trans_values.gray; if (g < ncols) { image.setAlphaBuffer(TRUE); image.setColor(g, image.color(g) & RGB_MASK); } } } } else if ( color_type == PNG_COLOR_TYPE_PALETTE && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE) && info_ptr->num_palette <= 256 ) { // 1-bit and 8-bit color if ( bit_depth != 1 ) png_set_packing( png_ptr ); png_read_update_info( png_ptr, info_ptr ); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (!image.create(width, height, bit_depth, info_ptr->num_palette, QImage::BigEndian)) return; int i = 0; if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ) { image.setAlphaBuffer( TRUE ); while ( i < info_ptr->num_trans ) { image.setColor(i, qRgba( info_ptr->palette[i].red, info_ptr->palette[i].green, info_ptr->palette[i].blue, info_ptr->trans[i] ) ); i++; } } while ( i < info_ptr->num_palette ) { image.setColor(i, qRgba( info_ptr->palette[i].red, info_ptr->palette[i].green, info_ptr->palette[i].blue, 0xff ) ); i++; } } else { // 32-bit if ( bit_depth == 16 ) png_set_strip_16(png_ptr); png_set_expand(png_ptr); if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb(png_ptr); if (!image.create(width, height, 32)) return; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xff, QImage::systemByteOrder() == QImage::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); // We want 4 bytes, but it isn't an alpha channel } else { image.setAlphaBuffer(TRUE); } if ( QImage::systemByteOrder() == QImage::BigEndian ) { png_set_swap_alpha(png_ptr); } png_read_update_info(png_ptr, info_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA) if ( QImage::systemByteOrder() == QImage::LittleEndian ) { png_set_bgr(png_ptr); } }
bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, const QString &description, int off_x_in, int off_y_in) { QPoint offset = image.offset(); int off_x = off_x_in + offset.x(); int off_y = off_y_in + offset.y(); png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { return false; } png_set_error_fn(png_ptr, 0, 0, qt_png_warning); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, 0); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return false; } int quality = quality_in; if (quality >= 0) { if (quality > 9) { qWarning("PNG: Quality %d out of range", quality); quality = 9; } png_set_compression_level(png_ptr, quality); } png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn); int color_type = 0; if (image.colorCount()) { if (image.isGrayscale()) color_type = PNG_COLOR_TYPE_GRAY; else color_type = PNG_COLOR_TYPE_PALETTE; } else if (image.format() == QImage::Format_Grayscale8) color_type = PNG_COLOR_TYPE_GRAY; else if (image.hasAlphaChannel()) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), image.depth() == 1 ? 1 : 8, // per channel color_type, 0, 0, 0); // sets #channels if (gamma != 0.0) { png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); } if (image.format() == QImage::Format_MonoLSB) png_set_packswap(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { // Paletted int num_palette = qMin(256, image.colorCount()); png_color palette[256]; png_byte trans[256]; int num_trans = 0; for (int i=0; i<num_palette; i++) { QRgb rgba=image.color(i); palette[i].red = qRed(rgba); palette[i].green = qGreen(rgba); palette[i].blue = qBlue(rgba); trans[i] = qAlpha(rgba); if (trans[i] < 255) { num_trans = i+1; } } png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if (num_trans) { png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0); } } // Swap ARGB to RGBA (normal PNG format) before saving on // BigEndian machines if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { png_set_swap_alpha(png_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless if (QSysInfo::ByteOrder == QSysInfo::LittleEndian && image.format() != QImage::Format_RGB888) { png_set_bgr(png_ptr); } if (off_x || off_y) { png_set_oFFs(png_ptr, info_ptr, off_x, off_y, PNG_OFFSET_PIXEL); } if (frames_written > 0) png_set_sig_bytes(png_ptr, 8); if (image.dotsPerMeterX() > 0 || image.dotsPerMeterY() > 0) { png_set_pHYs(png_ptr, info_ptr, image.dotsPerMeterX(), image.dotsPerMeterY(), PNG_RESOLUTION_METER); } set_text(image, png_ptr, info_ptr, description); png_write_info(png_ptr, info_ptr); if (image.depth() != 1) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888) png_set_filler(png_ptr, 0, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); if (looping >= 0 && frames_written == 0) { uchar data[13] = "NETSCAPE2.0"; // 0123456789aBC data[0xB] = looping%0x100; data[0xC] = looping/0x100; png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFx"), data, 13); } if (ms_delay >= 0 || disposal!=Unspecified) { uchar data[4]; data[0] = disposal; data[1] = 0; data[2] = (ms_delay/10)/0x100; // hundredths data[3] = (ms_delay/10)%0x100; png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFg"), data, 4); } int height = image.height(); int width = image.width(); switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: case QImage::Format_Grayscale8: case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: { png_bytep* row_pointers = new png_bytep[height]; for (int y=0; y<height; y++) row_pointers[y] = const_cast<png_bytep>(image.constScanLine(y)); png_write_image(png_ptr, row_pointers); delete [] row_pointers; } break; default: { QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32; QImage row; png_bytep row_pointers[1]; for (int y=0; y<height; y++) { row = image.copy(0, y, width, 1).convertToFormat(fmt); row_pointers[0] = const_cast<png_bytep>(row.constScanLine(0)); png_write_rows(png_ptr, row_pointers, 1); } } break; } png_write_end(png_ptr, info_ptr); frames_written++; png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { #ifdef USE_PNG destroy(); // First, check the PNG signature (if not set to skip it) if (!_skipSignature) { if (stream.readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { return false; } if (stream.readUint32BE() != MKTAG(0x0d, 0x0a, 0x1a, 0x0a)) { return false; } } // The following is based on the guide provided in: //http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3 //http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf // along with the png-loading code used in the sword25-engine. png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngPtr) { return false; } png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { png_destroy_read_struct(&pngPtr, NULL, NULL); return false; } png_set_error_fn(pngPtr, NULL, pngError, pngWarning); // TODO: The manual says errors should be handled via setjmp png_set_read_fn(pngPtr, &stream, pngReadFromStream); png_set_crc_action(pngPtr, PNG_CRC_DEFAULT, PNG_CRC_WARN_USE); // We already verified the PNG-header png_set_sig_bytes(pngPtr, 8); // Read PNG header png_read_info(pngPtr, infoPtr); // No handling for unknown chunks yet. int bitDepth, colorType, width, height, interlaceType; png_uint_32 w, h; png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL); width = w; height = h; // Allocate memory for the final image data. // To keep memory framentation low this happens before allocating memory for temporary image data. _outputSurface = new Graphics::Surface(); // Images of all color formats except PNG_COLOR_TYPE_PALETTE // will be transformed into ARGB images if (colorType == PNG_COLOR_TYPE_PALETTE && !png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { int numPalette = 0; png_colorp palette = NULL; uint32 success = png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette); if (success != PNG_INFO_PLTE) { png_destroy_read_struct(&pngPtr, &infoPtr, NULL); return false; } _paletteColorCount = numPalette; _palette = new byte[_paletteColorCount * 3]; for (int i = 0; i < _paletteColorCount; i++) { _palette[(i * 3)] = palette[i].red; _palette[(i * 3) + 1] = palette[i].green; _palette[(i * 3) + 2] = palette[i].blue; } _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); png_set_packing(pngPtr); } else { bool isAlpha = (colorType & PNG_COLOR_MASK_ALPHA); if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { isAlpha = true; png_set_expand(pngPtr); } _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, isAlpha ? 8 : 0, 24, 16, 8, 0)); if (!_outputSurface->getPixels()) { error("Could not allocate memory for output image."); } if (bitDepth == 16) png_set_strip_16(pngPtr); if (bitDepth < 8) png_set_expand(pngPtr); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(pngPtr); // PNGs are Big-Endian: #ifdef SCUMM_LITTLE_ENDIAN png_set_bgr(pngPtr); png_set_swap_alpha(pngPtr); if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) png_set_filler(pngPtr, 0xff, PNG_FILLER_BEFORE); #else if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER); #endif } // After the transformations have been registered, the image data is read again. png_set_interlace_handling(pngPtr); png_read_update_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); width = w; height = h; if (interlaceType == PNG_INTERLACE_NONE) { // PNGs without interlacing can simply be read row by row. for (int i = 0; i < height; i++) { png_read_row(pngPtr, (png_bytep)_outputSurface->getBasePtr(0, i), NULL); } } else { // PNGs with interlacing require us to allocate an auxillary // buffer with pointers to all row starts. // Allocate row pointer buffer png_bytep *rowPtr = new png_bytep[height]; if (!rowPtr) { error("Could not allocate memory for row pointers."); } // Initialize row pointers for (int i = 0; i < height; i++) rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); // Read image data png_read_image(pngPtr, rowPtr); // Free row pointer buffer delete[] rowPtr; } // Read additional data at the end. png_read_end(pngPtr, NULL); // Destroy libpng structures png_destroy_read_struct(&pngPtr, &infoPtr, NULL); return true; #else return false; #endif }
int read_PNG(char *file_name) { /* * Took this code from doc/fblib * and adjusted it to the likings * of this program. * ?i * It is really awesome that a NOOB * like me, Noisegate can actually * make useable software on an open * system like this Linux... * * openSOFtWARE rocKS */ png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 _width, _height, row; int bit_depth, color_type, interlace_type; FILE *fp; float screen_gamma; if ((fp = fopen(file_name, "rb")) == NULL) return -1; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ //png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); if (png_ptr == NULL){ fclose(fp); return -1; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return -1; } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ fprintf(stderr, "Error: Couldn't read the file."); return -1; } /* One of the following I/O initialization methods is REQUIRED */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* OK, you're doing it the hard way, with the lower-level functions */ /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &_width, &_height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* Set up the data transformations you want. Note that these are all * optional. Only call them if you want/need them. Many of the * transformations only work on specific types of images, and many * are mutually exclusive. */ /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ //png_set_strip_alpha(png_ptr); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one. */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); screen_gamma = 1.0; int intent; 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); } /* Invert monochrome files to have 0 as white and 1 as black */ png_set_invert_mono(png_ptr); /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit_p; png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); png_set_shift(png_ptr, sig_bit_p); } /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ png_set_swap_alpha(png_ptr); /* Swap bytes of 16 bit files to least significant byte first */ png_set_swap(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ png_set_filler(png_ptr, 0x00, PNG_FILLER_AFTER); /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ //number_passes = png_set_interlace_handling(png_ptr); /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (ie you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* Allocate the memory to hold the image using the fields of info_ptr. */ /* The easiest way to read the image: */ png_bytep row_pointers[_height]; /* Clear the pointer array */ for (row = 0; row < _height; row++) row_pointers[row] = NULL; for (row = 0; row < _height; row++) row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); /* Now it's time to read the image. One of these methods is REQUIRED */ png_read_image(png_ptr, row_pointers); /* Now mess this rowpointer thing into the tmp_buf * U dont know if width>_width and height>_height * so we trunc the guy */ int maxY = _height>height?height:_height; int maxX = _width>width?finfo.line_length:_width; int pix_offset=0; for (row=0; row<maxY;row++){ pix_offset = Ox*BPP + ((Oy+row)*finfo.line_length); memcpy(tmp_buf+pix_offset, row_pointers[row], maxX*BPP); } /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* At this point you have read the entire image */ /* Clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); /* Close the file */ fclose(fp); //printf("png W x H = %i x %i\n", _width, _height); /* That's it */ return 0; }
s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null) { if (cb_control_disp || disp_param) { throw EXCEPTION("Partial image decoding is not supported"); } // Indicate, that the PNG decoding is stopped/failed. This is incase, we return an error code in the middle of decoding data_out_info->status = CELL_PNGDEC_DEC_STATUS_STOP; // Possibilities for decoding in different sizes aren't tested, so if anyone finds any of these cases, we'll know about it. if (stream->info.imageWidth != stream->out_param.outputWidth) { throw EXCEPTION("Image width doesn't match output width! (%d/%d)", stream->out_param.outputWidth, stream->info.imageWidth); } if (stream->info.imageHeight != stream->out_param.outputHeight) { throw EXCEPTION("Image width doesn't match output height! (%d/%d)", stream->out_param.outputHeight, stream->info.imageHeight); } // Get the amount of output bytes per line const u32 bytes_per_line = data_control_param->outputBytesPerLine; // Whether to recaculate bytes per row bool recalculate_bytes_per_row = false; // Check if the game is expecting the number of bytes per line to be lower, than the actual bytes per line on the image. (Arkedo Pixel for example) // In such case we strip the bit depth to be lower. if ((bytes_per_line < stream->out_param.outputWidthByte) && stream->out_param.outputBitDepth != 8) { // Check if the packing is really 1 byte per 1 pixel if (stream->packing != CELL_PNGDEC_1BYTE_PER_1PIXEL) { throw EXCEPTION("Unexpected packing value! (%d)", stream->packing); } // Scale 16 bit depth down to 8 bit depth. PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then. png_set_strip_16(stream->png_ptr); recalculate_bytes_per_row = true; } // Check if the outputWidthByte is smaller than the intended output length of a line. For example an image might be in RGB, but we need to output 4 components, so we need to perform alpha padding. else if (stream->out_param.outputWidthByte < (stream->out_param.outputWidth * stream->out_param.outputComponents)) { // If fixed alpha is not specified in such a case, the default value for the alpha is 0xFF (255) if (!stream->fixed_alpha) { stream->fixed_alpha_colour = 0xFF; } // We need to fill alpha (before or after, depending on the output colour format) using the fixed alpha value passed by the game. png_set_add_alpha(stream->png_ptr, stream->fixed_alpha_colour, stream->out_param.outputColorSpace == CELL_PNGDEC_RGBA ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE); recalculate_bytes_per_row = true; } // We decode as RGBA, so we need to swap the alpha else if (stream->out_param.outputColorSpace == CELL_PNGDEC_ARGB) { // Swap the alpha channel for the ARGB output format, if the padding isn't needed png_set_swap_alpha(stream->png_ptr); } // Sometimes games pass in a RBG/RGBA image and want it as grayscale else if ((stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA || stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE) && (stream->info.colorSpace == CELL_PNGDEC_RGB || stream->info.colorSpace == CELL_PNGDEC_RGBA)) { // Tell libpng to convert it to grayscale png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); recalculate_bytes_per_row = true; } if (recalculate_bytes_per_row) { // Update the info structure png_read_update_info(stream->png_ptr, stream->info_ptr); // Recalculate the bytes per row stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr); } // Calculate the image size u32 image_size = stream->out_param.outputWidthByte * stream->out_param.outputHeight; // Buffer for storing the image std::vector<u8> png(image_size); // Make an unique pointer for the row pointers std::vector<u8*> row_pointers(stream->out_param.outputHeight); // Allocate memory for rows for (u32 y = 0; y < stream->out_param.outputHeight; y++) { row_pointers[y] = &png[y * stream->out_param.outputWidthByte]; } // Decode the image png_read_image(stream->png_ptr, row_pointers.data()); // Check if the image needs to be flipped const bool flip = stream->out_param.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP; // Copy the result to the output buffer switch (stream->out_param.outputColorSpace) { case CELL_PNGDEC_RGB: case CELL_PNGDEC_RGBA: case CELL_PNGDEC_ARGB: case CELL_PNGDEC_GRAYSCALE_ALPHA: { // Check if we need to flip the image or need to leave empty bytes at the end of a line if ((bytes_per_line > stream->out_param.outputWidthByte) || flip) { // Get how many bytes per line we need to output - bytesPerLine is total amount of bytes per line, rest is unused and the game can do as it pleases. const u32 line_size = std::min(bytes_per_line, stream->out_param.outputWidth * 4); // If the game wants more bytes per line to be output, than the image has, then we simply copy what we have for each line, // and continue on the next line, thus leaving empty bytes at the end of the line. for (u32 i = 0; i < stream->out_param.outputHeight; i++) { const u32 dst = i * bytes_per_line; const u32 src = stream->out_param.outputWidth * 4 * (flip ? stream->out_param.outputHeight - i - 1 : i); memcpy(&data[dst], &png[src], line_size); } } else { // We can simply copy the output to the data pointer specified by the game, since we already do alpha channel transformations in libpng, if needed memcpy(data.get_ptr(), png.data(), image_size); } break; } default: throw EXCEPTION("Unsupported color space (%d)", stream->out_param.outputColorSpace); } // Get the number of iTXt, tEXt and zTXt chunks s32 text_chunks = 0; png_get_text(stream->png_ptr, stream->info_ptr, nullptr, &text_chunks); // Set the chunk information and the previously obtained number of text chunks data_out_info->numText = (u32)text_chunks; data_out_info->chunkInformation = pngDecGetChunkInformation(stream, true); data_out_info->numUnknownChunk = 0; // TODO: Get this somehow. Does anything even use or need this? // Indicate that the decoding succeeded data_out_info->status = CELL_PNGDEC_DEC_STATUS_FINISH; return CELL_OK; }
static struct XenosSurface *loadPNGFromMemory(unsigned char *PNGdata) { int y = 0; int width, height; png_byte color_type; png_byte bit_depth; png_structp png_ptr; png_infop info_ptr; // int number_of_passes; png_bytep * row_pointers; offset = 0; struct file_buffer_t *file; file = (struct file_buffer_t *) malloc(sizeof (struct file_buffer_t)); file->length = 1024 * 1024 * 5; file->data = (unsigned char *) malloc(file->length); //5mo ... file->offset = 0; memcpy(file->data, PNGdata, file->length); /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("[read_png_file] png_create_read_struct failed\n"); return 0; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("[read_png_file] png_create_info_struct failed\n"); return 0; } png_set_read_fn(png_ptr, (png_voidp *) file, png_mem_read); //permet de lire à partir de pngfile buff //png_set_sig_bytes(png_ptr, 8);//on avance de 8 ? png_read_info(png_ptr, info_ptr); width = info_ptr->width; height = info_ptr->height; color_type = info_ptr->color_type; bit_depth = info_ptr->bit_depth; // number_of_passes = png_set_interlace_handling(png_ptr); if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) { printf("no support :( \n bit_depth = %08x\n", bit_depth); return 0; } if (color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xFF, PNG_FILLER_BEFORE); png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); //On créer la surface struct XenosSurface *surface = Xe_CreateTexture(g_pVideoDevice, width, height, 1, XE_FMT_8888 | XE_FMT_ARGB, 0); uint8_t *data = (uint8_t*) Xe_Surface_LockRect(g_pVideoDevice, surface, 0, 0, 0, 0, XE_LOCK_WRITE); row_pointers = (png_bytep*) malloc(sizeof (png_bytep) * surface->height); for (y = 0; y < surface->height; y++) row_pointers[y] = data + surface->wpitch * y; png_read_image(png_ptr, row_pointers); Xe_Surface_Unlock(g_pVideoDevice, surface); free(file->data); free(file); free(row_pointers); return surface; }
bool MCImageEncodePNG(MCImageBitmap *p_bitmap, IO_handle p_stream, uindex_t &r_bytes_written) { bool t_success = true; MCPNGWriteContext t_context; t_context.stream = p_stream; t_context.byte_count = 0; png_structp t_png_ptr = nil; png_infop t_info_ptr = nil; png_color *t_png_palette = nil; png_byte *t_png_transparency = nil; png_bytep t_data_ptr = nil; uindex_t t_stride = 0; MCImageIndexedBitmap *t_indexed = nil; if (MCImageConvertBitmapToIndexed(p_bitmap, false, t_indexed)) { t_success = MCImageEncodePNG(t_indexed, p_stream, r_bytes_written); MCImageFreeIndexedBitmap(t_indexed); return t_success; } /*init png stuff*/ if (t_success) { t_success = nil != (t_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL)); } if (t_success) t_success = nil != (t_info_ptr = png_create_info_struct(t_png_ptr)); /*in case of png error*/ if (setjmp(png_jmpbuf(t_png_ptr))) t_success = false; if (t_success) png_set_write_fn(t_png_ptr,(png_voidp)&t_context,fakewrite,fakeflush); bool t_fully_opaque = true; if (t_success) { t_fully_opaque = !MCImageBitmapHasTransparency(p_bitmap); png_set_IHDR(t_png_ptr, t_info_ptr, p_bitmap->width, p_bitmap->height, 8, t_fully_opaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_gAMA(t_png_ptr, t_info_ptr, 1/MCgamma); } if (t_success) { png_write_info(t_png_ptr, t_info_ptr); //32 bit compensate for byte swapped systems if (t_fully_opaque) png_set_filler(t_png_ptr, 0, MCswapbytes ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE); if (MCswapbytes) png_set_bgr(t_png_ptr); else png_set_swap_alpha(t_png_ptr); } if (t_success) { t_data_ptr = (png_bytep)p_bitmap->data; t_stride = p_bitmap->stride; } if (t_success) { for (uindex_t i = 0; i < p_bitmap->height; i++) { png_write_row(t_png_ptr, t_data_ptr); t_data_ptr += t_stride; } } if (t_success) png_write_end(t_png_ptr, t_info_ptr); if (t_png_ptr != nil) png_destroy_write_struct(&t_png_ptr, &t_info_ptr); if (t_png_palette != nil) MCMemoryDeleteArray(t_png_palette); if (t_png_transparency != nil) MCMemoryDeallocate(t_png_transparency); if (t_success) r_bytes_written = t_context.byte_count; return t_success; }
ARGB *png_LoadFrame(void *ptrCache, int index){ //printf("æasdgnlhæskljgælSDKJGÆKLSjdgljfg\n"); png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; char *name; //posix_printf("png Loading frame %d\n",index); DynamicArray* daPtr; PngImgData* pidPtr; daPtr=(DynamicArray*)ptrCache; pidPtr=(PngImgData*)daPtr->GetItem(index); name=pidPtr->ImgName; //posix_printf("LoadFrame imagename: %s\n", pidPtr->ImgName); if ((fp = fopen(/*"C:\\Games\\Game\\Textures\\Rock0000.png"*/name, "rb")) == NULL) return NULL; //posix_printf("1\n"); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //posix_printf("2\n"); if (png_ptr == NULL){ fclose(fp); return NULL; } //posix_printf("3\n"); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL){ fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } //posix_printf("4\n"); if (setjmp(png_ptr->jmpbuf)){ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return NULL; } //posix_printf("5\n"); png_init_io(png_ptr, fp); //posix_printf("6\n"); png_read_info(png_ptr, info_ptr); //posix_printf("7\n"); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); //posix_printf("8\n"); if (bit_depth==16){ printf("Stripping to 8 bits\n"); png_set_strip_16(png_ptr); } /* expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets */{ //posix_printf("9\n"); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) // printf("Expanding tRNS\n"); png_set_expand(png_ptr); } //posix_printf("10\n"); if (color_type == PNG_COLOR_TYPE_PALETTE){ // posix_printf("Expanding palette\n"); int channels=png_get_channels(png_ptr, info_ptr); // posix_printf("Channels: %d\n", channels); png_set_expand(png_ptr); } //posix_printf("11\n"); if ((color_type == PNG_COLOR_TYPE_RGB) && (bit_depth==8)){ posix_printf("Bit depth==8 og RGB\n"); png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); } //posix_printf("12\n"); if (color_type==PNG_COLOR_TYPE_RGB_ALPHA){ // posix_printf("RGB w/ Alpha. Switching to ARGB\n"); png_set_swap_alpha(png_ptr); } //posix_printf("13\n"); if (bit_depth<8){ posix_printf("Bitdepth < 8\n"); png_set_packing(png_ptr); } //printf("----- %d\n",color_type); //posix_printf("14\n"); png_read_update_info(png_ptr, info_ptr); //posix_printf("15\n"); /* allocate the memory to hold the image using the fields of info_ptr. */ /* the easiest way to read the image */ png_bytep *row_pointers = (png_bytep*)malloc(sizeof(png_bytep)*height); for (int row=0; row<height; row++){ //posix_printf("row %d, bytes %d\n",row,png_get_rowbytes(png_ptr, info_ptr)); png_bytep foo = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr)); //posix_printf("%x\n",foo); row_pointers[row] = foo; } //posix_printf("15\n"); png_read_image(png_ptr, row_pointers); //posix_printf("16\n"); png_read_end(png_ptr, info_ptr); png_bytep rowPtr; ARGB *argbPtr=(ARGB*)malloc(sizeof(ARGB)*width*height); ARGB *ptr = argbPtr; for (int i=0; i<height; i++){ rowPtr=row_pointers[i]; for (int j=0; j<width; j++){ ARGB col; if (color_type==PNG_COLOR_TYPE_PALETTE) col.A=1.0f; else col.A = ((float)*rowPtr++)/256.0f; col.R = ((float)*rowPtr++)/256.0f; col.G = ((float)*rowPtr++)/256.0f; col.B = ((float)*rowPtr++)/256.0f; *ptr++=col; //printf("Row: %d A: %f R: %f G: %f B: %f\n", i, argbPtr->A, argbPtr->R, argbPtr->G, argbPtr->B); //argbPtr++; } } for(row=0; row<height; row++){ free(row_pointers[row]); } //posix_printf("17\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); //posix_printf("18\n"); free(row_pointers); return argbPtr; }
void PNGAPI png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms, voidp params) { int row; if (png_ptr == NULL) return; /* png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) png_error(png_ptr, "Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ #ifdef PNG_READ_16_TO_8_SUPPORTED /* Tell libpng to strip 16 bit/color files down to 8 bits per color. */ if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED /* Strip alpha bytes from the input data without combining with * the background (not recommended). */ if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); #endif #ifdef PNG_READ_PACKSWAP_SUPPORTED /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ if (transforms & PNG_TRANSFORM_EXPAND) if ((png_ptr->bit_depth < 8) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); #endif /* We don't handle background color or gamma transformation or quantizing. */ #ifdef PNG_READ_INVERT_SUPPORTED /* Invert monochrome files to have 0 as white and 1 as black */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #ifdef PNG_READ_SHIFT_SUPPORTED /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if ((transforms & PNG_TRANSFORM_SHIFT) && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } #endif #ifdef PNG_READ_BGR_SUPPORTED /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #ifdef PNG_READ_SWAP_SUPPORTED /* Swap bytes of 16 bit files to least significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif /* Added at libpng-1.2.41 */ #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel from opacity to transparency */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif /* Added at libpng-1.2.41 */ #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale image to RGB */ if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) png_set_gray_to_rgb(png_ptr); #endif /* We don't handle adding filler bytes */ /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (i.e., you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* -------------- image transformations end here ------------------- */ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); if (info_ptr->row_pointers == NULL) { png_uint_32 iptr; info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, info_ptr->height * png_sizeof(png_bytep)); for (iptr=0; iptr<info_ptr->height; iptr++) info_ptr->row_pointers[iptr] = NULL; info_ptr->free_me |= PNG_FREE_ROWS; for (row = 0; row < (int)info_ptr->height; row++) info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } png_read_image(png_ptr, info_ptr->row_pointers); info_ptr->valid |= PNG_INFO_IDAT; /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); transforms = transforms; /* Quiet compiler warnings */ params = params; }
Texture* PNGLoader::load(string fileName, bool mipMaps) { png_structp png_ptr; png_infop info_ptr; unsigned long sig_read = 0; int bit_depth, color_type, interlace_type; png_uint_32 width, height; unsigned short components; // Load file from disk FILE* file = fopen(fileName.c_str(), "rb"); if (file == NULL) return NULL; // Create png read and info structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(file); return NULL; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(NULL); return NULL; } // Set up the function to read bytes from file stream png_set_read_fn(png_ptr, file, png_read_file_data); png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*) &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // Adjust image format if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (bit_depth < 8) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_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); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*)&height, &bit_depth, &color_type, NULL, NULL, NULL); if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { #ifdef __BIG_ENDIAN__ png_set_swap_alpha(png_ptr); #else png_set_bgr(png_ptr); #endif } png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*) &height, &bit_depth, &color_type, NULL, NULL, NULL); // Store the components amount if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) components = 32; else components = 24; // Start reading from buffer png_byte** row = new png_byte*[height]; png_byte* buffer = new png_byte[width * height * (components / 8)]; png_byte* it = buffer; for (png_uint_32 i = 0; i < height; i++) { row[i] = it; it += width * (components / 8); } png_read_image(png_ptr, row); png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); Texture* tex = new Texture(buffer, width, height, components, mipMaps); delete [] row; delete [] buffer; fclose(file); return tex; }