bool wxPNGHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) { // VZ: as this function uses setjmp() the only fool-proof error handling // method is to use goto (setjmp is not really C++ dtors friendly...) unsigned char **lines = NULL; png_infop info_ptr = (png_infop) NULL; wxPNGInfoStruct wxinfo; png_uint_32 i, width, height = 0; int bit_depth, color_type, interlace_type; wxinfo.verbose = verbose; wxinfo.stream.in = &stream; image->Destroy(); png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, NULL, wx_PNG_error, wx_PNG_warning ); if (!png_ptr) goto error; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) goto error; if (setjmp(wxinfo.jmpbuf)) goto error; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->IsOk()) goto error; // initialize all line pointers to NULL to ensure that they can be safely // free()d if an error occurs before all of them could be allocated lines = (unsigned char **)calloc(height, sizeof(unsigned char *)); if ( !lines ) goto error; for (i = 0; i < height; i++) { if ((lines[i] = (unsigned char *)malloc( (size_t)(width * 4))) == NULL) goto error; } png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); #if wxUSE_PALETTE if (color_type == PNG_COLOR_TYPE_PALETTE) { png_colorp palette = NULL; int numPalette = 0; (void) png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette); unsigned char* r = new unsigned char[numPalette]; unsigned char* g = new unsigned char[numPalette]; unsigned char* b = new unsigned char[numPalette]; for (int j = 0; j < numPalette; j++) { r[j] = palette[j].red; g[j] = palette[j].green; b[j] = palette[j].blue; } image->SetPalette(wxPalette(numPalette, r, g, b)); delete[] r; delete[] g; delete[] b; } #endif // wxUSE_PALETTE // set the image resolution if it's available png_uint_32 resX, resY; int unitType; if (png_get_pHYs(png_ptr, info_ptr, &resX, &resY, &unitType) == PNG_INFO_pHYs) { wxImageResolution res = wxIMAGE_RESOLUTION_CM; switch (unitType) { default: wxLogWarning(_("Unknown PNG resolution unit %d"), unitType); // fall through case PNG_RESOLUTION_UNKNOWN: image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, resX); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, resY); res = wxIMAGE_RESOLUTION_NONE; break; case PNG_RESOLUTION_METER: /* Convert meters to centimeters. Use a string to not lose precision (converting to cm and then to inch would result in integer rounding error). If an app wants an int, GetOptionInt will convert and round down for them. */ image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, wxString::FromCDouble((double) resX / 100.0, 2)); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, wxString::FromCDouble((double) resY / 100.0, 2)); break; } image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, res); } png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); for ( i = 0; i < height; i++ ) free( lines[i] ); free( lines ); return true; error: if (verbose) { wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); } if ( image->IsOk() ) { image->Destroy(); } if ( lines ) { for ( unsigned int n = 0; n < height; n++ ) free( lines[n] ); free( lines ); } if ( png_ptr ) { if ( info_ptr ) { png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); free(info_ptr); } else png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); } return false; }
// This function uses wxPNGImageData to store some of its "local" variables in // order to avoid clobbering these variables by longjmp(): having them inside // the stack frame of the caller prevents this from happening. It also // "returns" its result via wxPNGImageData: use its "ok" field to check // whether loading succeeded or failed. void wxPNGImageData::DoLoadPNGFile(wxImage* image, wxPNGInfoStruct& wxinfo) { png_uint_32 width, height = 0; int bit_depth, color_type, interlace_type; image->Destroy(); png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, NULL, wx_PNG_error, wx_PNG_warning ); if (!png_ptr) return; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) return; if (setjmp(wxinfo.jmpbuf)) return; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->IsOk()) return; if ( !Alloc(width, height) ) return; png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); #if wxUSE_PALETTE if (color_type == PNG_COLOR_TYPE_PALETTE) { png_colorp palette = NULL; int numPalette = 0; (void) png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette); unsigned char* r = new unsigned char[numPalette]; unsigned char* g = new unsigned char[numPalette]; unsigned char* b = new unsigned char[numPalette]; for (int j = 0; j < numPalette; j++) { r[j] = palette[j].red; g[j] = palette[j].green; b[j] = palette[j].blue; } image->SetPalette(wxPalette(numPalette, r, g, b)); delete[] r; delete[] g; delete[] b; } #endif // wxUSE_PALETTE // set the image resolution if it's available png_uint_32 resX, resY; int unitType; if (png_get_pHYs(png_ptr, info_ptr, &resX, &resY, &unitType) == PNG_INFO_pHYs) { wxImageResolution res = wxIMAGE_RESOLUTION_CM; switch (unitType) { default: wxLogWarning(_("Unknown PNG resolution unit %d"), unitType); wxFALLTHROUGH; case PNG_RESOLUTION_UNKNOWN: image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, resX); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, resY); res = wxIMAGE_RESOLUTION_NONE; break; case PNG_RESOLUTION_METER: /* Convert meters to centimeters. Use a string to not lose precision (converting to cm and then to inch would result in integer rounding error). If an app wants an int, GetOptionInt will convert and round down for them. */ image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, wxString::FromCDouble((double) resX / 100.0, 2)); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, wxString::FromCDouble((double) resY / 100.0, 2)); break; } image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, res); } // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); // This will indicate to the caller that loading succeeded. ok = true; }
bool wxPNGHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) { // VZ: as this function uses setjmp() the only fool-proof error handling // method is to use goto (setjmp is not really C++ dtors friendly...) unsigned char **lines = NULL; png_infop info_ptr = (png_infop) NULL; wxPNGInfoStruct wxinfo; png_uint_32 i, width, height = 0; int bit_depth, color_type, interlace_type; wxinfo.verbose = verbose; wxinfo.stream.in = &stream; image->Destroy(); png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, (voidp) NULL, wx_png_error, wx_png_warning ); if (!png_ptr) goto error; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) goto error; if (setjmp(wxinfo.jmpbuf)) goto error; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->Ok()) goto error; // initialize all line pointers to NULL to ensure that they can be safely // free()d if an error occurs before all of them could be allocated lines = (unsigned char **)calloc(height, sizeof(unsigned char *)); if ( !lines ) goto error; for (i = 0; i < height; i++) { if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) goto error; } png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); #if wxUSE_PALETTE if (color_type == PNG_COLOR_TYPE_PALETTE) { const size_t ncolors = info_ptr->num_palette; unsigned char* r = new unsigned char[ncolors]; unsigned char* g = new unsigned char[ncolors]; unsigned char* b = new unsigned char[ncolors]; for (size_t j = 0; j < ncolors; j++) { r[j] = info_ptr->palette[j].red; g[j] = info_ptr->palette[j].green; b[j] = info_ptr->palette[j].blue; } image->SetPalette(wxPalette(ncolors, r, g, b)); delete[] r; delete[] g; delete[] b; } #endif // wxUSE_PALETTE png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); for ( i = 0; i < height; i++ ) free( lines[i] ); free( lines ); return true; error: if (verbose) { wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); } if ( image->Ok() ) { image->Destroy(); } if ( lines ) { for ( unsigned int n = 0; n < height; n++ ) free( lines[n] ); free( lines ); } if ( png_ptr ) { if ( info_ptr ) { png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); free(info_ptr); } else png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); } return false; }
bool wxPNGHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) { // VZ: as this function uses setjmp() the only fool proof error handling // method is to use goto (setjmp is not really C++ dtors friendly...) unsigned char **lines = NULL; png_infop info_ptr = (png_infop) NULL; wxPNGInfoStruct wxinfo; wxinfo.verbose = verbose; wxinfo.stream.in = &stream; image->Destroy(); png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, (voidp) NULL, wx_png_error, wx_png_warning ); if (!png_ptr) goto error; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) goto error; if (setjmp(wxinfo.jmpbuf)) goto error; png_uint_32 i, width, height; int bit_depth, color_type, interlace_type; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->Ok()) goto error; lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) ); if ( !lines ) goto error; for (i = 0; i < height; i++) { if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) { for ( unsigned int n = 0; n < i; n++ ) free( lines[n] ); goto error; } } png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); for ( i = 0; i < height; i++ ) free( lines[i] ); free( lines ); return true; error: if (verbose) wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); if ( image->Ok() ) { image->Destroy(); } if ( lines ) { free( lines ); } if ( png_ptr ) { if ( info_ptr ) { png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); free(info_ptr); } else png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); } return false; }